diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 97996e66c3..c036f36c37 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -12,8 +12,9 @@
+
+
-
@@ -46,6 +47,7 @@
+
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000000..bbf8c992fb
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,35 @@
+# APP 壳
+
+## 加载模块
+
+## 初始化部分服务
+
+## 定义 flavor
+
+### basic 维度
+
+产品形态:区别 applicationId,定义服务加载
+
+1. independent:独立app,作为普通 app 运行在系统
+2. launcher:作为 launcher 运行在系统
+
+### product 维度
+
+产品线,各个产品线引入不同服务,实现不同服务内容
+
+1. f8xx: 分体机 - launcher
+2. e8xx: E系列m4(2+32) - launcher
+3. em4: E系列m4(2+32) - launcher
+4. em3: E系列m3(2+32) - independent
+5. em1: E系列m1(1+16) - independent
+6. d8xx: D系列(2+32) - independent
+7. d82x: D系列(1+16) - independent
+8. byd: 比亚迪应用市场 - independent
+
+### env 维度
+
+1. online: 线上环境
+2. qa: 测试环境
+3. demo: 演示环境(大部分时候都是测试环境)
+
+## 区分 flavor 功能引入
diff --git a/app/build.gradle b/app/build.gradle
index a6f1083172..53594ea272 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -25,7 +25,7 @@ android {
externalNativeBuild {
ndk {
// 设置支持的SO库架构
- abiFilters 'armeabi-v7a'
+ abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
}
}
@@ -82,8 +82,8 @@ android {
applicationId rootProject.ext.android.independentApplicationId
// 是否启动位置服务
buildConfigField 'boolean', 'LAUNCH_LOCATION_SERVICE', 'false'
- // 是否使用自定义导航
- buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
+ // 是否使用高德sdk自定义导航
+ buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'true'
// 是否作为 launcher 运行
buildConfigField 'boolean', 'IS_LAUNCHER', 'false'
}
@@ -93,7 +93,7 @@ android {
applicationId rootProject.ext.android.launcherApplicationId
// 是否启动位置服务
buildConfigField 'boolean', 'LAUNCH_LOCATION_SERVICE', 'true'
- // 是否使用自定义导航
+ // 是否使用高德sdk自定义导航
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'true'
// 是否作为 launcher 运行
buildConfigField 'boolean', 'IS_LAUNCHER', 'true'
@@ -246,7 +246,6 @@ dependencies {
implementation rootProject.ext.dependencies.carcallprovider
implementation rootProject.ext.dependencies.carcall
- implementation rootProject.ext.dependencies.moduleV2x
implementation rootProject.ext.dependencies.moduletanlu, {
exclude group: 'com.mogo.module', module: 'module-share'
}
@@ -268,6 +267,7 @@ dependencies {
implementation rootProject.ext.dependencies.modulemedia
implementation rootProject.ext.dependencies.moduleservice
implementation rootProject.ext.dependencies.modulesplash
+ implementation rootProject.ext.dependencies.moduleV2x
// 事件面板分渠道引用
d82xImplementation rootProject.ext.dependencies.moduleventpanelnoop
em1Implementation rootProject.ext.dependencies.moduleventpanelnoop
@@ -301,6 +301,7 @@ dependencies {
implementation project(':modules:mogo-module-media')
implementation project(':modules:mogo-module-service')
implementation project(':modules:mogo-module-splash')
+ implementation project(':modules:mogo-module-v2x')
// 事件面板分渠道引用
d82xImplementation project(':modules:mogo-module-event-panel-noop')
em1Implementation project(':modules:mogo-module-event-panel-noop')
@@ -320,6 +321,8 @@ dependencies {
f8xxImplementation project(':modules:mogo-module-left-panel-noop')
em3Implementation project(':modules:mogo-module-left-panel-noop')
}
+
+ apply from: "./functions/baseservices.gradle"
}
//android.applicationVariants.all { variant ->
diff --git a/app/functions/README.md b/app/functions/README.md
new file mode 100644
index 0000000000..27064aa5d3
--- /dev/null
+++ b/app/functions/README.md
@@ -0,0 +1 @@
+# 不同渠道,依赖的实现不一样,需要各个渠道都去依赖各自需要的实现,渠道太多导致build.gradle 文件臃肿,可以通过分gradle文件方式减少臃肿
\ No newline at end of file
diff --git a/app/functions/baseservices.gradle b/app/functions/baseservices.gradle
new file mode 100644
index 0000000000..8a6726e463
--- /dev/null
+++ b/app/functions/baseservices.gradle
@@ -0,0 +1,26 @@
+// 基础服务:仅比亚迪渠道用sdk方式实现,其他都基于apk基础服务
+
+project.dependencies {
+ if (Boolean.valueOf(RELEASE)) {
+ bydImplementation rootProject.ext.dependencies.mogobaseservicesdk
+
+ d82xImplementation rootProject.ext.dependencies.mogobaseserviceapk
+ em1Implementation rootProject.ext.dependencies.mogobaseserviceapk
+ d8xxImplementation rootProject.ext.dependencies.mogobaseserviceapk
+ em4Implementation rootProject.ext.dependencies.mogobaseserviceapk
+ e8xxImplementation rootProject.ext.dependencies.mogobaseserviceapk
+ e8xxImplementation rootProject.ext.dependencies.mogobaseserviceapk
+ f8xxImplementation rootProject.ext.dependencies.mogobaseserviceapk
+ em3Implementation rootProject.ext.dependencies.mogobaseserviceapk
+ } else {
+ bydImplementation project(':foudations:mogo-base-services-sdk')
+
+ d82xImplementation project(':foudations:mogo-base-services-apk')
+ em1Implementation project(':foudations:mogo-base-services-apk')
+ d8xxImplementation project(':foudations:mogo-base-services-apk')
+ em4Implementation project(':foudations:mogo-base-services-apk')
+ e8xxImplementation project(':foudations:mogo-base-services-apk')
+ f8xxImplementation project(':foudations:mogo-base-services-apk')
+ em3Implementation project(':foudations:mogo-base-services-apk')
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mogo/launcher/MogoApplication.java b/app/src/main/java/com/mogo/launcher/MogoApplication.java
index 50d5971763..c2904fda00 100644
--- a/app/src/main/java/com/mogo/launcher/MogoApplication.java
+++ b/app/src/main/java/com/mogo/launcher/MogoApplication.java
@@ -9,6 +9,8 @@ import com.auto.zhidao.logsdk.CrashSystem;
import com.bytedance.boost_multidex.BoostMultiDex;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.debug.DebugConfig;
+import com.mogo.map.location.IMogoLocationListener;
+import com.mogo.map.location.MogoLocation;
import com.mogo.module.authorize.authprovider.invoke.AuthorizeConstant;
import com.mogo.module.carchatting.card.CallChatConstant;
import com.mogo.module.common.MogoModule;
@@ -19,8 +21,12 @@ import com.mogo.module.push.base.PushUIConstants;
import com.mogo.module.service.ServiceConst;
import com.mogo.module.tanlu.constant.TanluConstants;
import com.mogo.module.v2x.V2XConst;
+import com.mogo.service.IMogoServiceApis;
import com.mogo.service.MogoServicePaths;
import com.mogo.service.connection.IMogoSocketManager;
+import com.mogo.service.passport.IMogoPassportManager;
+import com.mogo.service.passport.IMogoTicketCallback;
+import com.mogo.utils.UiThreadHandler;
import com.mogo.utils.logger.LogLevel;
import com.mogo.utils.logger.Logger;
import com.zhidao.boot.persistent.lib.PersistentManager;
@@ -43,66 +49,79 @@ public class MogoApplication extends AbsMogoApplication {
super.onCreate();
// Crash 日志收集
final long start = System.currentTimeMillis();
- CrashSystem crashSystem = CrashSystem.getInstance(this);
+ CrashSystem crashSystem = CrashSystem.getInstance( this );
crashSystem.init();
//设置debug模式,日志不上传
- crashSystem.setDebug(BuildConfig.DEBUG);
- Logger.init(BuildConfig.DEBUG ? LogLevel.DEBUG : LogLevel.OFF);
+ crashSystem.setDebug( BuildConfig.DEBUG );
+ Logger.init( BuildConfig.DEBUG ? LogLevel.DEBUG : LogLevel.OFF );
// MogoModulePaths.addModule(new MogoModule(PATH_GUIDE_FRAGMENT, PATH_GUIDE_MODULE_NAME));
- MogoModulePaths.addModule(new MogoModule(AuthorizeConstant.PATH_AGREEMENT_FRAGMENT, AuthorizeConstant.PATH_AGREEMENT_MODULE_NAME));
+ MogoModulePaths.addModule( new MogoModule( AuthorizeConstant.PATH_AGREEMENT_FRAGMENT, AuthorizeConstant.PATH_AGREEMENT_MODULE_NAME ) );
//运营位卡片,需要默认显示,放在第一个加载
- if (DebugConfig.isLauncher()) {
- MogoModulePaths.addModule(new MogoModule(MediaConstants.TAG, MediaConstants.MODULE_TYPE));
+ if ( DebugConfig.isLauncher() ) {
+ MogoModulePaths.addModule( new MogoModule( MediaConstants.TAG, MediaConstants.MODULE_TYPE ) );
}
- MogoModulePaths.addModule(new MogoModule(CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME));
- MogoModulePaths.addModule(new MogoModule(TanluConstants.TAG, TanluConstants.MODEL_NAME));
- MogoModulePaths.addModule(new MogoModule(MogoServicePaths.PATH_SHARE, "ShareControl"));
+ MogoModulePaths.addModule( new MogoModule( CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME ) );
+ MogoModulePaths.addModule( new MogoModule( TanluConstants.TAG, TanluConstants.MODEL_NAME ) );
+ MogoModulePaths.addModule( new MogoModule( MogoServicePaths.PATH_SHARE, "ShareControl" ) );
- MogoModulePaths.addModule(new MogoModule(EventPanelConstants.PATH_NAME,
- EventPanelConstants.MODULE_NAME));
- MogoModulePaths.addModule(new MogoModule(LeftPanelConst.PATH_NAME,
- LeftPanelConst.MODULE_NAME));
+ MogoModulePaths.addModule( new MogoModule( EventPanelConstants.PATH_NAME,
+ EventPanelConstants.MODULE_NAME ) );
+ MogoModulePaths.addModule( new MogoModule( LeftPanelConst.PATH_NAME,
+ LeftPanelConst.MODULE_NAME ) );
MogoModulePaths.addBaseModule( new MogoModule( ServiceConst.PATH_REFRESH_STRATEGY, ServiceConst.PATH_REFRESH_STRATEGY ) );
MogoModulePaths.addBaseModule( new MogoModule( V2XConst.PATH_V2X_UI, V2XConst.PATH_V2X_UI ) );
- MogoModulePaths.addModule(new MogoModule( PushUIConstants.PATH, PushUIConstants.NAME));
+ MogoModulePaths.addModule( new MogoModule( PushUIConstants.PATH, PushUIConstants.NAME ) );
- if (!DebugConfig.isLauncher()) {
- PersistentManager.getInstance().initManager(this);
- Intent intent = new Intent(this, MogoMainService.class);
- startService(intent);
+ if ( !DebugConfig.isLauncher() ) {
+ PersistentManager.getInstance().initManager( this );
+ Intent intent = new Intent( this, MogoMainService.class );
+ startService( intent );
}
- Log.i("timer", "cost " + (System.currentTimeMillis() - start) + "ms");
+ Log.i( "timer", "cost " + ( System.currentTimeMillis() - start ) + "ms" );
}
- private void initDebugConfig(){
- DebugConfig.setNetMode(BuildConfig.NET_ENV);
- DebugConfig.setDebug(BuildConfig.DEBUG);
- DebugConfig.setAIType(BuildConfig.AIType);
- DebugConfig.setLaunchLocationService(BuildConfig.LAUNCH_LOCATION_SERVICE);
- DebugConfig.setUseCustomNavi(BuildConfig.USE_CUSTOM_NAVI);
- DebugConfig.setLauncher(BuildConfig.IS_LAUNCHER);
+ private void initDebugConfig() {
+ DebugConfig.setNetMode( BuildConfig.NET_ENV );
+ DebugConfig.setDebug( BuildConfig.DEBUG );
+ DebugConfig.setAIType( BuildConfig.AIType );
+ DebugConfig.setLaunchLocationService( BuildConfig.LAUNCH_LOCATION_SERVICE );
+ DebugConfig.setUseCustomNavi( BuildConfig.USE_CUSTOM_NAVI );
+ DebugConfig.setLauncher( BuildConfig.IS_LAUNCHER );
DebugConfig.setActiveAIAssistFlag( BuildConfig.AI_ASSIST_ACTIVE_STAUTS );
- DebugConfig.setCarMachineType(BuildConfig.CAR_MACHINE_TYPE);
+ DebugConfig.setCarMachineType( BuildConfig.CAR_MACHINE_TYPE );
}
@Override
protected void init() {
super.init();
- IMogoSocketManager mMogoSocketManager = ARouter.getInstance().navigation(IMogoSocketManager.class);
- if (mMogoSocketManager != null) {
- mMogoSocketManager.init(getApplicationContext(), "com.mogo.launcher");
- } else {
- Logger.e(TAG, "init socket server error.");
- }
+ UiThreadHandler.postDelayed( () -> {
+ final IMogoServiceApis apis = ARouter.getInstance().navigation( IMogoServiceApis.class );
+ apis.getSocketManagerApi( getApplicationContext() ).init( getApplicationContext(), "com.mogo.launcher" );
+ apis.getPassportManagerApi().requestTicket( new IMogoTicketCallback() {
+ @Override
+ public void onSuccess( String ticket ) {
+ Logger.d( TAG, "ticket = %s", ticket );
+ }
+
+ @Override
+ public void onError( int code, String msg ) {
+ Logger.w( TAG, "code = %s, msg = %s", code, msg );
+ }
+ } );
+ apis.getLocationInfoApi().start();
+ apis.getMapServiceApi().getSingletonLocationClient( getApplicationContext() ).addLocationListener( location -> {
+ apis.getLocationInfoApi().provideLocation( location );
+ } );
+ }, 2_000L );
}
@Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- BoostMultiDex.install(base);
+ protected void attachBaseContext( Context base ) {
+ super.attachBaseContext( base );
+ BoostMultiDex.install( base );
}
}
diff --git a/config.gradle b/config.gradle
index 683dc75b5c..555c961b34 100644
--- a/config.gradle
+++ b/config.gradle
@@ -4,12 +4,12 @@ ext {
android = [
// applicationId : "com.mogo.launcher",
// zhidadoApplicationId: "com.zhidao.launcher",
- launcherApplicationId : "com.mogo.launcher",
- independentApplicationId: "com.mogo.launcher.app",
- compileSdkVersion : 28,
- buildToolsVersion : "29.0.2",
- minSdkVersion : 19,
- targetSdkVersion : 22,
+launcherApplicationId : "com.mogo.launcher",
+independentApplicationId: "com.mogo.launcher.app",
+compileSdkVersion : 28,
+buildToolsVersion : "29.0.2",
+minSdkVersion : 19,
+targetSdkVersion : 22,
]
dependencies = [
@@ -21,6 +21,8 @@ ext {
androidxviewpager2 : "androidx.viewpager2:viewpager2:1.0.0",
androidxrecyclerview : "androidx.recyclerview:recyclerview:1.1.0",
androidxcardview : "androidx.cardview:cardview:1.0.0",
+ // flexbox
+ flexbox : 'com.google.android:flexbox:2.0.1',
// 测试
junit : "junit:junit:4.12",
androidxjunit : "androidx.test.ext:junit:1.1.0",
@@ -73,11 +75,6 @@ ext {
// rxjava2 with room
roomRxjava : "android.arch.persistence.room:rxjava2:1.1.1",
-
- // leakcanary
- leakcanary : 'com.squareup.leakcanary:leakcanary-android:1.5.4',
- leakcanarynoop : 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4',
-
// material
material : 'com.google.android.material:material:1.0.0',
@@ -172,5 +169,9 @@ ext {
moduleleftpanelnoop : "com.mogo.module:module-left-panel-noop:${MOGO_MODULE_LEFT_PANEL_VERSION}",
// 闪屏页
modulesplash : "com.mogo.module:module-splash:${MOGO_MODULE_SPLASH_VERSION}",
+
+ // 基础服务实现
+ mogobaseservicesdk : "com.mogo.base:services-apk:${MOGO_BASE_SERVICES_SDK_VERSION}",
+ mogobaseserviceapk : "com.mogo.base:services-sdk:${MOGO_BASE_SERVICES_APK_VERSION}",
]
}
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/.gitignore b/foudations/mogo-base-services-apk/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/foudations/mogo-base-services-apk/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/README.md b/foudations/mogo-base-services-apk/README.md
new file mode 100644
index 0000000000..b6ee9eafae
--- /dev/null
+++ b/foudations/mogo-base-services-apk/README.md
@@ -0,0 +1,7 @@
+## 基实现功能
+
+基础服务apk实现对应功能:位置上报、长连接、passport
+
+位置上报:com.zhidao.locationinfo
+长链:com.zhidao.socketservice
+passport:
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/build.gradle b/foudations/mogo-base-services-apk/build.gradle
new file mode 100644
index 0000000000..943521aac6
--- /dev/null
+++ b/foudations/mogo-base-services-apk/build.gradle
@@ -0,0 +1,51 @@
+apply plugin: 'com.android.library'
+
+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"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation rootProject.ext.dependencies.arouter
+
+ api rootProject.ext.dependencies.socketsdk
+ api rootProject.ext.dependencies.socketsdkconnsvrprotoco
+ api rootProject.ext.dependencies.socketsdkprotobufjava
+ implementation rootProject.ext.dependencies.accountsdk
+
+ if (Boolean.valueOf(RELEASE)) {
+ implementation rootProject.ext.dependencies.mogoutils
+ implementation rootProject.ext.dependencies.mogocommons
+ implementation rootProject.ext.dependencies.mogoserviceapi
+ } else {
+ implementation project(":foudations:mogo-utils")
+ implementation project(":foudations:mogo-commons")
+ implementation project(":services:mogo-service-api")
+ }
+
+}
+
+apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/consumer-rules.pro b/foudations/mogo-base-services-apk/consumer-rules.pro
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/foudations/mogo-base-services-apk/gradle.properties b/foudations/mogo-base-services-apk/gradle.properties
new file mode 100644
index 0000000000..aae1d6638c
--- /dev/null
+++ b/foudations/mogo-base-services-apk/gradle.properties
@@ -0,0 +1,3 @@
+GROUP=com.mogo.base
+POM_ARTIFACT_ID=services-apk
+VERSION_CODE=1
diff --git a/foudations/mogo-base-services-apk/proguard-rules.pro b/foudations/mogo-base-services-apk/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/foudations/mogo-base-services-apk/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/foudations/mogo-base-services-apk/src/androidTest/java/com/mogo/base/services/apk/ExampleInstrumentedTest.java b/foudations/mogo-base-services-apk/src/androidTest/java/com/mogo/base/services/apk/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000..3588462fba
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/androidTest/java/com/mogo/base/services/apk/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.mogo.base.services.apk;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith( AndroidJUnit4.class )
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals( "com.mogo.base.services.apk.test", appContext.getPackageName() );
+ }
+}
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/src/main/AndroidManifest.xml b/foudations/mogo-base-services-apk/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..a82c409551
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+ /
+
\ No newline at end of file
diff --git a/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java
new file mode 100644
index 0000000000..5a6c31d624
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java
@@ -0,0 +1,63 @@
+package com.mogo.base.services.locationinfo;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+
+import com.mogo.map.location.MogoLocation;
+import com.mogo.service.locationinfo.IMogoLocationInfoService;
+import com.mogo.utils.logger.Logger;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 位置服务
+ */
+@Keep
+class MogoLocationInfoServices implements IMogoLocationInfoService {
+
+ private static final String TAG = "MogoLocationInfoServices-apk";
+
+ private static volatile MogoLocationInfoServices sInstance;
+
+ private MogoLocationInfoServices() {
+ }
+
+ @Keep
+ public static MogoLocationInfoServices getInstance() {
+ if ( sInstance == null ) {
+ synchronized ( MogoLocationInfoServices.class ) {
+ if ( sInstance == null ) {
+ sInstance = new MogoLocationInfoServices();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ public synchronized void release() {
+ sInstance = null;
+ }
+
+ @Override
+ public void provideLocation( MogoLocation location ) {
+ Logger.d( TAG, "apk - provideLocation" );
+ }
+
+ @Override
+ public void start() {
+ Logger.d( TAG, "apk - start" );
+ }
+
+ @Override
+ public void stop() {
+ Logger.d( TAG, "apk - stop" );
+ }
+
+ @Override
+ public void init( Context context ) {
+ Logger.d( TAG, "apk - init" );
+ }
+}
diff --git a/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/passport/PassportManager.java b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/passport/PassportManager.java
new file mode 100644
index 0000000000..5090b53910
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/passport/PassportManager.java
@@ -0,0 +1,87 @@
+package com.mogo.base.services.passport;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.storage.SpStorage;
+import com.mogo.service.passport.IMogoPassportManager;
+import com.mogo.service.passport.IMogoTicketCallback;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.account.sdk.AccountClientManager;
+import com.zhidao.account.sdk.callback.TicketInfoCallback;
+import com.zhidao.account.sdk.network.NetEnvironManager;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 描述
+ */
+@Keep
+class PassportManager implements IMogoPassportManager {
+
+ private static final String TAG = "PassportManager-apk";
+
+ private static volatile PassportManager sInstance;
+
+ private PassportManager(){}
+
+ @Keep
+ public static PassportManager getInstance(){
+ if( sInstance == null ){
+ synchronized( PassportManager.class ) {
+ if( sInstance == null ){
+ sInstance = new PassportManager();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ public synchronized void release(){
+ sInstance = null;
+ }
+
+ @Override
+ public void requestTicket( final IMogoTicketCallback callback ) {
+ getTicket( new TicketInfoCallback() {
+ @Override
+ public void onSuccess( String ticket ) {
+ Logger.d( TAG, "success" );
+ SpStorage.setTicket( ticket );
+ if ( callback != null ) {
+ callback.onSuccess( ticket );
+ }
+ }
+
+ @Override
+ public void onFailure( int code, String msg ) {
+ Logger.d( TAG, "fail" );
+ if ( callback != null ) {
+ callback.onError( code, msg );
+ }
+ }
+ } );
+ }
+
+ private static void getTicket( TicketInfoCallback callback ) {
+ if ( DebugConfig.isLauncher() ) {
+ AccountClientManager.getTicket( callback );
+ } else {
+ AccountClientManager.getAppTicket( callback );
+ }
+ }
+
+ @Override
+ public void init( Context context ) {
+ int mode = DebugConfig.getNetMode();
+ if ( mode == DebugConfig.NET_MODE_DEMO ) {
+ // 演示环境用 qa 的
+ mode = DebugConfig.NET_MODE_QA;
+ }
+ AccountClientManager.init( context.getApplicationContext(), mode, NetEnvironManager.OS_2C, "os2.0-launcher" );
+ }
+}
diff --git a/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/socket/SocketManager.java b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/socket/SocketManager.java
new file mode 100644
index 0000000000..f2db841a0a
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/main/java/com/mogo/base/services/socket/SocketManager.java
@@ -0,0 +1,224 @@
+package com.mogo.base.services.socket;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mogo.service.connection.IMogoMsgAckListener;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.service.connection.IMogoSocketManager;
+import com.mogo.service.connection.MsgBody;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.network.utils.GsonUtil;
+import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
+import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
+import com.zhidao.socketsdk.manager.OnSocketAckCallback;
+import com.zhidao.socketsdk.manager.OnSocketReceiveCallback;
+import com.zhidao.socketsdk.manager.SocketConnManager;
+import com.zhidao.socketsdk.manager.SocketConnManagerImpl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author congtaowang
+ * @since 2019-12-31
+ *
+ * 长链实现:基于 netty
+ */
+@Keep
+public class SocketManager implements IMogoSocketManager, OnSocketReceiveCallback, OnSocketAckCallback {
+
+ private static final String TAG = "SocketManager-apk";
+
+ public static final int MSG_PRODUCT_LINE = MogoCommon.Product.mogoBussiness_VALUE;
+ private static final int MSG_HEADER_TYPE = MogoConnsvr.MsgType.mogoMsgTypeDispatchSvrNoRspReq_VALUE;
+
+ private static volatile SocketManager sInstance;
+
+ private SocketManager( Context context ) {
+ mSocketConnManager = SocketConnManagerImpl.getInstance( context );
+ mSocketConnManager.addSocketMessageCallback( this );
+ mSocketConnManager.addSocketAckCallback( this );
+ }
+
+ @Keep
+ public static SocketManager getInstance( Context context ) {
+ if ( sInstance == null ) {
+ synchronized ( SocketManager.class ) {
+ if ( sInstance == null ) {
+ sInstance = new SocketManager( context );
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * 管理消息分发
+ *
+ * key - msgType
+ */
+ private Map< Integer, List< IMogoOnMessageListener > > mListeners = new ConcurrentHashMap<>();
+
+ /**
+ * 管理消息回执
+ *
+ * key - msgId
+ */
+ private Map< Long, IMogoMsgAckListener > mAckListeners = new ConcurrentHashMap<>();
+
+
+ private SocketConnManager mSocketConnManager;
+ public static final int MAX_CAP = 64; //保证充足的容量应对非常延时的推送
+ private ArrayList< Long > mReceivedMsgId = new ArrayList<>( MAX_CAP );
+ private int mCurrentIndex = 0;
+
+ @Override
+ public void init( Context context, String appId ) {
+ if ( mSocketConnManager != null ) {
+ mSocketConnManager.init( appId );
+ }
+ }
+
+ @Override
+ public void onMessageReceived( byte[] content, long msgId ) {
+ try {
+ MogoConnsvr.Payload payload = MogoConnsvr.Payload.parseFrom( content );
+ int msgType = payload.getMsgType();
+ Logger.d( TAG, "received msg type = %d", msgType );
+ List< IMogoOnMessageListener > listeners = mListeners.get( msgType );
+ if ( listeners != null && !listeners.isEmpty() ) {
+ Iterator< IMogoOnMessageListener > iterator = listeners.iterator();
+ if ( msgId != 0 ) { //兼容老版本
+ if ( mReceivedMsgId.contains( msgId ) ) { // 避免消息重发
+ return;
+ }
+ cacheLastReceivedMsgId( msgId );
+ }
+ Object object = null;
+ while ( iterator.hasNext() ) {
+ IMogoOnMessageListener listener = iterator.next();
+ if ( object == null ) {
+ object = GsonUtil.objectFromJson( payload.getPayload().toStringUtf8(), listener.target() );
+ }
+ if ( listener != null ) {
+ Logger.d( TAG, "received msgId = %s, content = %s", msgId, payload.getPayload().toStringUtf8() );
+ listener.onMsgReceived( object );
+ }
+ }
+ }
+ } catch ( InvalidProtocolBufferException e ) {
+ Logger.e( TAG, e, "parse msg error." );
+ }
+ }
+
+ private void cacheLastReceivedMsgId( long msgId ) {
+ if ( msgId == 0 ) {
+ return;
+ }
+ synchronized ( this ){
+ mReceivedMsgId.add( mCurrentIndex % MAX_CAP, msgId );
+ mCurrentIndex++;
+ }
+ }
+
+ @Override
+ public void onAck( byte[] headerBytes, byte[] payloadBytes ) {
+ try {
+ MogoConnsvr.Header header = MogoConnsvr.Header.parseFrom( headerBytes );
+ int msgType = header.getMsgType();
+ String appId = header.getAppId();
+ int productLine = header.getProductLine();
+ long msgId = header.getMsgId();
+ IMogoMsgAckListener listener = mAckListeners.remove( msgId );
+ if ( listener != null ) {
+ listener.onAck( msgId );
+ }
+ Logger.d( TAG, "send message success: msgType = %d, appId = %s, productLine = %d", msgType, appId, productLine );
+ } catch ( InvalidProtocolBufferException e ) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void registerOnMessageListener( int msgType, IMogoOnMessageListener listener ) {
+ if ( mListeners.containsKey( msgType ) ) {
+ Logger.w( TAG, "msgType %d is exist.", msgType );
+ }
+ if ( !mListeners.containsKey( msgType ) ) {
+ mListeners.put( msgType, new ArrayList< IMogoOnMessageListener >() );
+ }
+ mListeners.get( msgType ).add( listener );
+ }
+
+ @Override
+ public void unregisterOnMessageListener( int msgType ) {
+ mListeners.remove( msgType );
+ }
+
+ @Override
+ public void unregisterOnMessageListener( int msgType, IMogoOnMessageListener listener ) {
+ if ( listener == null ) {
+ return;
+ }
+ if ( !mListeners.containsKey( msgType ) ) {
+ return;
+ }
+ List< IMogoOnMessageListener > listeners = mListeners.get( msgType );
+ if ( listeners != null && listeners.contains( listener ) ) {
+ listeners.remove( listener );
+ }
+ }
+
+ @Override
+ public void sendMsg( MsgBody body, IMogoMsgAckListener listener ) {
+ Logger.d( TAG, "sendMsg." );
+ if ( mSocketConnManager != null ) {
+ if ( mSocketConnManager.isConnected() ) {
+ Logger.d( TAG, "isConnected." );
+ final byte[] pb = convertToPBBytes( body.getMsgType(), objectToBytes( body.getContent() ) );
+ mSocketConnManager.sendPayload(
+ MSG_PRODUCT_LINE,
+ pb,
+ MSG_HEADER_TYPE,
+ body.isAck(),
+ body.getMsgId()
+ );
+ mAckListeners.put( body.getMsgId(), listener );
+ } else {
+ Logger.e( TAG, "sendMsg error, connect is lost." );
+ }
+ } else {
+ Logger.e( TAG, "sendMsg error, client is null." );
+ }
+ }
+
+ public byte[] objectToBytes( Object obj ) {
+ String jsonStr = GsonUtil.jsonFromObject( obj );
+ return jsonStr.getBytes();
+ }
+
+ private byte[] convertToPBBytes( int msgType, byte[] payloadBytes ) {
+ MogoConnsvr.Payload payloadData = MogoConnsvr.Payload.newBuilder()
+ .setMsgType( msgType )
+ .setPayload( ByteString.copyFrom( payloadBytes ) ).build();
+ return payloadData.toByteArray();
+ }
+
+ public synchronized void release() {
+ mListeners.clear();
+ mListeners = null;
+ sInstance = null;
+ }
+
+
+ @Override
+ public void init( Context context ) {
+ }
+}
diff --git a/foudations/mogo-base-services-apk/src/test/java/com/mogo/base/services/apk/ExampleUnitTest.java b/foudations/mogo-base-services-apk/src/test/java/com/mogo/base/services/apk/ExampleUnitTest.java
new file mode 100644
index 0000000000..7b81601a73
--- /dev/null
+++ b/foudations/mogo-base-services-apk/src/test/java/com/mogo/base/services/apk/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.mogo.base.services.apk;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals( 4, 2 + 2 );
+ }
+}
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/.gitignore b/foudations/mogo-base-services-sdk/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/README.md b/foudations/mogo-base-services-sdk/README.md
new file mode 100644
index 0000000000..d5fa09de5b
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/README.md
@@ -0,0 +1,3 @@
+## sdk实现功能
+
+脱离基础服务apk实现对应功能:位置上报、长连接、passport
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/build.gradle b/foudations/mogo-base-services-sdk/build.gradle
new file mode 100644
index 0000000000..1dd7e70249
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/build.gradle
@@ -0,0 +1,53 @@
+apply plugin: 'com.android.library'
+
+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"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation rootProject.ext.dependencies.arouter
+ // 上报位置
+ implementation 'com.zhidao.locupload:loc-upload-sdk:1.0.6'
+ // 长链
+ implementation 'com.zhidao.socket:built-in-socket:1.0.11'
+ // passport
+ implementation 'com.zhidao.tcloginsdk:tclogin:1.0.6'
+
+ annotationProcessor 'com.elegant.spi:compiler:1.0.3'
+
+
+ if (Boolean.valueOf(RELEASE)) {
+ implementation rootProject.ext.dependencies.mogoutils
+ implementation rootProject.ext.dependencies.mogocommons
+ implementation rootProject.ext.dependencies.mogoserviceapi
+ } else {
+ implementation project(":foudations:mogo-utils")
+ implementation project(":foudations:mogo-commons")
+ implementation project(":services:mogo-service-api")
+ }
+}
+
+apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/consumer-rules.pro b/foudations/mogo-base-services-sdk/consumer-rules.pro
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/foudations/mogo-base-services-sdk/gradle.properties b/foudations/mogo-base-services-sdk/gradle.properties
new file mode 100644
index 0000000000..a753d03b00
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/gradle.properties
@@ -0,0 +1,3 @@
+GROUP=com.mogo.connection
+POM_ARTIFACT_ID=mogo-base-services-sdk
+VERSION_CODE=1
diff --git a/foudations/mogo-base-services-sdk/proguard-rules.pro b/foudations/mogo-base-services-sdk/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/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/foudations/mogo-base-services-sdk/src/androidTest/java/com/mogo/base/services/ExampleInstrumentedTest.java b/foudations/mogo-base-services-sdk/src/androidTest/java/com/mogo/base/services/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000..856a560f77
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/androidTest/java/com/mogo/base/services/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.mogo.base.services;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith( AndroidJUnit4.class )
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals( "com.mogo.base.services.test", appContext.getPackageName() );
+ }
+}
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/src/main/AndroidManifest.xml b/foudations/mogo-base-services-sdk/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..d7ee25b198
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+ /
+
\ No newline at end of file
diff --git a/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java
new file mode 100644
index 0000000000..754ab1cbfa
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationInfoServices.java
@@ -0,0 +1,98 @@
+package com.mogo.base.services.locationinfo;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+
+import com.elegant.spi.annotations.Service;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.service.locationinfo.IMogoLocationInfoService;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.locupload.LocEnvironment;
+import com.zhidao.locupload.LocUploadConfig;
+import com.zhidao.locupload.LocUploadManager;
+import com.zhidao.locupload.Platform;
+import com.zhidao.locupload.location.LocationServiceProvider;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 位置服务
+ */
+@Keep
+class MogoLocationInfoServices implements IMogoLocationInfoService {
+
+ private static final String TAG = "MogoLocationInfoServices-sdk";
+
+ private static volatile MogoLocationInfoServices sInstance;
+ private MogoLocation mLocation;
+
+ private MogoLocationInfoServices() {
+ }
+
+ @Keep
+ public static MogoLocationInfoServices getInstance() {
+ if ( sInstance == null ) {
+ synchronized ( MogoLocationInfoServices.class ) {
+ if ( sInstance == null ) {
+ sInstance = new MogoLocationInfoServices();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ public synchronized void release() {
+ sInstance = null;
+ }
+
+ @Override
+ public void provideLocation( MogoLocation location ) {
+ mLocation = location;
+ Logger.d(TAG, "sdk - provideLocation");
+ }
+
+ public MogoLocation getLocation() {
+ return mLocation;
+ }
+
+ @Override
+ public void start() {
+ LocUploadManager.getInstance().startUpload();
+ Logger.d(TAG, "sdk - start");
+ }
+
+ @Override
+ public void stop() {
+ LocUploadManager.getInstance().stopUpload();
+ Logger.d(TAG, "sdk - stop");
+ }
+
+ @Override
+ public void init( Context context ) {
+ LocUploadConfig.instance().
+ setAppId( "dataCrawler" ).
+ setContext( context.getApplicationContext() ).
+ setLocEnvironment( getEnvironment() ).
+ setLoggable( DebugConfig.isDebug() ).
+ setPlatform( Platform.car ).
+ setLocInterval( 2000L );
+ Logger.d(TAG, "sdk - init");
+ }
+
+ private LocEnvironment getEnvironment() {
+ switch ( DebugConfig.getNetMode() ) {
+ case 1:
+ return LocEnvironment.dev;
+ case 2:
+ case 4:
+ return LocEnvironment.qa;
+ case 3:
+ default:
+ return LocEnvironment.release;
+ }
+ }
+}
diff --git a/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationSource.java b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationSource.java
new file mode 100644
index 0000000000..844abb4a98
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/locationinfo/MogoLocationSource.java
@@ -0,0 +1,133 @@
+package com.mogo.base.services.locationinfo;
+
+import com.elegant.spi.annotations.Service;
+import com.zhidao.locupload.location.LocationServiceProvider;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 描述
+ */
+@Service( value = LocationServiceProvider.class )
+class MogoLocationSource extends LocationServiceProvider {
+
+ @Override
+ public float getBearing() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getBearing();
+ }
+ return 0;
+ }
+
+ @Override
+ public float getAccuracy() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getAccuracy();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getProvider() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getProvider();
+ }
+ return null;
+ }
+
+ @Override
+ public float getSpeed() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getSpeed();
+ }
+ return 0;
+ }
+
+ @Override
+ public double getAltitude() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getAltitude();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getAdCode() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getAdCode();
+ }
+ return null;
+ }
+
+ @Override
+ public int getLocType() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getLocType();
+ }
+ return 0;
+ }
+
+ @Override
+ public double getLatitude() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getLatitude();
+ }
+ return 0;
+ }
+
+ @Override
+ public double getLongitude() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getLongitude();
+ }
+ return 0;
+ }
+
+ @Override
+ public long getTime() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getTime();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getCityCode() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getCityCode();
+ }
+ return null;
+ }
+
+ @Override
+ public String getCityName() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getCityName();
+ }
+ return null;
+ }
+
+ @Override
+ public int getGpsAccuracyStatus() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getGpsAccuracyStatus();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getSatellites() {
+ if ( MogoLocationInfoServices.getInstance().getLocation() != null ) {
+ return MogoLocationInfoServices.getInstance().getLocation().getSatellite();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getCarStatus() {
+ // 常开状态
+ return 1;
+ }
+}
diff --git a/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/passport/PassportManager.java b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/passport/PassportManager.java
new file mode 100644
index 0000000000..184b63c7a6
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/passport/PassportManager.java
@@ -0,0 +1,101 @@
+package com.mogo.base.services.passport;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.storage.SpStorage;
+import com.mogo.service.passport.IMogoPassportManager;
+import com.mogo.service.passport.IMogoTicketCallback;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.accountsdk.manager.CarPadClientManagerImpl;
+import com.zhidao.accountsdk.manager.TicketInfoCallback;
+import com.zhidao.accountsdk.network.NetEnvironManager;
+import com.zhidao.tcloginsdk.ToCLoginManagerImpl;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 描述
+ */
+@Keep
+class PassportManager implements IMogoPassportManager {
+
+ private static final String TAG = "PassportManager-sdk";
+ private Context mContext;
+
+ private static volatile PassportManager sInstance;
+
+ private PassportManager(){}
+
+ @Keep
+ public static PassportManager getInstance(){
+ if( sInstance == null ){
+ synchronized( PassportManager.class ) {
+ if( sInstance == null ){
+ sInstance = new PassportManager();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ public synchronized void release(){
+ sInstance = null;
+ }
+
+ @Override
+ public void requestTicket( final IMogoTicketCallback callback ) {
+ getTicket( new TicketInfoCallback() {
+ @Override
+ public void onSuccess( String ticket ) {
+ Logger.d( TAG, "success" );
+ SpStorage.setTicket( ticket );
+ if ( callback != null ) {
+ callback.onSuccess( ticket );
+ }
+ }
+
+ @Override
+ public void onFailure( int code ) {
+ Logger.d( TAG, "fail" );
+ if ( callback != null ) {
+ callback.onError( code, "error." );
+ }
+ }
+ } );
+ }
+
+ private void getTicket( TicketInfoCallback callback ) {
+ CarPadClientManagerImpl.getInstance( mContext ).getTicket( "os2.0-launcher", new TicketInfoCallback() {
+ @Override
+ public void onSuccess( String ticket ) {
+ if ( callback != null ) {
+ callback.onSuccess( ticket );
+ }
+ }
+
+ @Override
+ public void onFailure( int code ) {
+ if ( callback != null ) {
+ callback.onFailure( code );
+ }
+ }
+ } );
+ }
+
+ @Override
+ public void init( Context context ) {
+ mContext = context;
+ int mode = DebugConfig.getNetMode();
+ if ( mode == DebugConfig.NET_MODE_DEMO ) {
+ // 演示环境用 qa 的
+ mode = DebugConfig.NET_MODE_QA;
+ }
+ ToCLoginManagerImpl.getInstance( context ).setNetEnviron( mode );
+ ToCLoginManagerImpl.getInstance( context ).showLoginView();
+ }
+}
diff --git a/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/socket/SocketManager.java b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/socket/SocketManager.java
new file mode 100644
index 0000000000..cc3574b3bc
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/main/java/com/mogo/base/services/socket/SocketManager.java
@@ -0,0 +1,227 @@
+package com.mogo.base.services.socket;
+
+import android.content.Context;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.service.connection.IMogoMsgAckListener;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.service.connection.IMogoSocketManager;
+import com.mogo.service.connection.MsgBody;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.network.utils.GsonUtil;
+import com.zhidao.locupload.Platform;
+import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
+import com.zhidao.socket.Callback;
+import com.zhidao.socket.CallbackManager;
+import com.zhidao.socket.Environment;
+import com.zhidao.socket.SocketConfig;
+import com.zhidao.socket.SocketMessageDispatcher;
+import com.zhidao.socket.utils.RequestUtil;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public
+/**
+ * @author congtaowang
+ * @since 2020/7/16
+ *
+ * 长链
+ */
+@Keep
+class SocketManager implements IMogoSocketManager, Callback {
+
+ private static final String TAG = "SocketManager-sdk";
+
+ private static volatile SocketManager sInstance;
+ private String mAppId;
+
+ public SocketManager( Context context ) {
+ CallbackManager.getInstance().register( this );
+ }
+
+ @Keep
+ public static SocketManager getInstance( Context context ) {
+ if ( sInstance == null ) {
+ synchronized ( SocketManager.class ) {
+ if ( sInstance == null ) {
+ sInstance = new SocketManager( context );
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * 管理消息分发
+ *
+ * key - msgType
+ */
+ private Map< Integer, List< IMogoOnMessageListener > > mListeners = new ConcurrentHashMap<>();
+
+ /**
+ * 管理消息回执
+ *
+ * key - msgId
+ */
+ private Map< Long, IMogoMsgAckListener > mAckListeners = new ConcurrentHashMap<>();
+
+
+ public static final int MAX_CAP = 64; //保证充足的容量应对非常延时的推送
+ private ArrayList< Long > mReceivedMsgId = new ArrayList<>( MAX_CAP );
+ private int mCurrentIndex = 0;
+
+ @Override
+ public void init( Context context, String appId ) {
+ mAppId = appId;
+ SocketConfig.instance()
+ .setAppContext( context.getApplicationContext() )
+ .setEnvironment( getEnvironment() )
+ .setClient( Platform.getClient( Platform.car ) )
+ .setAppId( appId )
+ .setDebug( DebugConfig.isDebug() );
+ SocketMessageDispatcher.getInstance().start( context );
+ }
+
+ private Environment getEnvironment() {
+ switch ( DebugConfig.getNetMode() ) {
+ case 1:
+ return Environment.dev;
+ case 2:
+ case 4:
+ return Environment.qa;
+ case 3:
+ default:
+ return Environment.release;
+ }
+ }
+
+ @Override
+ public void update( @NonNull CallbackManager manager, @NonNull byte[] content, String appId, long msgId ) {
+ try {
+ MogoConnsvr.Payload payload = MogoConnsvr.Payload.parseFrom( content );
+ int msgType = payload.getMsgType();
+ Logger.d( TAG, "received msg type = %d", msgType );
+ List< IMogoOnMessageListener > listeners = mListeners.get( msgType );
+ if ( listeners != null && !listeners.isEmpty() ) {
+ Iterator< IMogoOnMessageListener > iterator = listeners.iterator();
+ if ( msgId != 0 ) { //兼容老版本
+ if ( mReceivedMsgId.contains( msgId ) ) { // 避免消息重发
+ return;
+ }
+ cacheLastReceivedMsgId( msgId );
+ }
+ Object object = null;
+ while ( iterator.hasNext() ) {
+ IMogoOnMessageListener listener = iterator.next();
+ if ( object == null ) {
+ object = GsonUtil.objectFromJson( payload.getPayload().toStringUtf8(), listener.target() );
+ }
+ if ( listener != null ) {
+ Logger.d( TAG, "received msgId = %s, content = %s", msgId, payload.getPayload().toStringUtf8() );
+ listener.onMsgReceived( object );
+ }
+ }
+ }
+ } catch ( InvalidProtocolBufferException e ) {
+ Logger.e( TAG, e, "parse msg error." );
+ }
+ }
+
+ @Override
+ public void onAck( @NonNull CallbackManager manager, @NonNull byte[] headerBytes, byte[] content ) {
+ try {
+ MogoConnsvr.Header header = MogoConnsvr.Header.parseFrom( headerBytes );
+ int msgType = header.getMsgType();
+ String appId = header.getAppId();
+ int productLine = header.getProductLine();
+ long msgId = header.getMsgId();
+ IMogoMsgAckListener listener = mAckListeners.remove( msgId );
+ if ( listener != null ) {
+ listener.onAck( msgId );
+ }
+ Logger.d( TAG, "send message success: msgType = %d, appId = %s, productLine = %d", msgType, appId, productLine );
+ } catch ( InvalidProtocolBufferException e ) {
+ e.printStackTrace();
+ }
+ }
+
+ private void cacheLastReceivedMsgId( long msgId ) {
+ if ( msgId == 0 ) {
+ return;
+ }
+ synchronized ( this ) {
+ mReceivedMsgId.add( mCurrentIndex % MAX_CAP, msgId );
+ mCurrentIndex++;
+ }
+ }
+
+ @Override
+ public void registerOnMessageListener( int msgType, IMogoOnMessageListener listener ) {
+ if ( mListeners.containsKey( msgType ) ) {
+ Logger.w( TAG, "msgType %d is exist.", msgType );
+ }
+ if ( !mListeners.containsKey( msgType ) ) {
+ mListeners.put( msgType, new ArrayList< IMogoOnMessageListener >() );
+ }
+ mListeners.get( msgType ).add( listener );
+ }
+
+ @Override
+ public void unregisterOnMessageListener( int msgType ) {
+ mListeners.remove( msgType );
+ }
+
+ @Override
+ public void unregisterOnMessageListener( int msgType, IMogoOnMessageListener listener ) {
+ if ( listener == null ) {
+ return;
+ }
+ if ( !mListeners.containsKey( msgType ) ) {
+ return;
+ }
+ List< IMogoOnMessageListener > listeners = mListeners.get( msgType );
+ if ( listeners != null && listeners.contains( listener ) ) {
+ listeners.remove( listener );
+ }
+ }
+
+ @Override
+ public void sendMsg( MsgBody body, IMogoMsgAckListener listener ) {
+ Logger.d( TAG, "sendMsg." );
+ final byte[] pb = convertToPBBytes( body.getMsgType(), objectToBytes( body.getContent() ) );
+ RequestUtil.sendPayloadData( mAppId, 2, pb, 1, true, System.currentTimeMillis() );
+ }
+
+ public byte[] objectToBytes( Object obj ) {
+ String jsonStr = GsonUtil.jsonFromObject( obj );
+ return jsonStr.getBytes();
+ }
+
+ private byte[] convertToPBBytes( int msgType, byte[] payloadBytes ) {
+ MogoConnsvr.Payload payloadData = MogoConnsvr.Payload.newBuilder()
+ .setMsgType( msgType )
+ .setPayload( ByteString.copyFrom( payloadBytes ) ).build();
+ return payloadData.toByteArray();
+ }
+
+ public synchronized void release() {
+ mListeners.clear();
+ mListeners = null;
+ sInstance = null;
+ }
+
+
+ @Override
+ public void init( Context context ) {
+ }
+
+}
diff --git a/foudations/mogo-base-services-sdk/src/test/java/com/mogo/base/services/ExampleUnitTest.java b/foudations/mogo-base-services-sdk/src/test/java/com/mogo/base/services/ExampleUnitTest.java
new file mode 100644
index 0000000000..ec74ef013f
--- /dev/null
+++ b/foudations/mogo-base-services-sdk/src/test/java/com/mogo/base/services/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.mogo.base.services;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals( 4, 2 + 2 );
+ }
+}
\ No newline at end of file
diff --git a/foudations/mogo-commons/src/main/java/com/mogo/commons/AbsMogoApplication.java b/foudations/mogo-commons/src/main/java/com/mogo/commons/AbsMogoApplication.java
index 943ad1417d..c38e5425c7 100644
--- a/foudations/mogo-commons/src/main/java/com/mogo/commons/AbsMogoApplication.java
+++ b/foudations/mogo-commons/src/main/java/com/mogo/commons/AbsMogoApplication.java
@@ -1,9 +1,7 @@
package com.mogo.commons;
import android.app.Application;
-import android.content.Context;
import android.text.TextUtils;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@@ -20,11 +18,7 @@ import com.mogo.commons.network.X509TrustManagerImpl;
import com.mogo.commons.storage.SpStorage;
import com.mogo.utils.ThreadPoolService;
import com.mogo.utils.TipToast;
-import com.mogo.utils.logger.Logger;
import com.mogo.utils.network.NetConfig;
-import com.zhidao.account.sdk.AccountClientManager;
-import com.zhidao.account.sdk.callback.TicketInfoCallback;
-import com.zhidao.account.sdk.network.NetEnvironManager;
import java.io.IOException;
import java.security.SecureRandom;
@@ -98,7 +92,6 @@ public class AbsMogoApplication extends Application {
private void asyncInit() {
ThreadPoolService.execute( () -> {
initNetConfig();
- initAccountSdk();
// 初始化toast
// 初始化埋点
Analytics.getInstance().start( sApp );
@@ -109,37 +102,42 @@ public class AbsMogoApplication extends Application {
AnalyticsConfig.getInstance( sApp ).shouldLog( DebugConfig.isDebug() );
Devices.init( getApp() );
Devices.checkBindState();
+ asyncInitImpl();
} );
}
- private static void initAccountSdk() {
- int mode = DebugConfig.getNetMode();
- if ( mode == DebugConfig.NET_MODE_DEMO ) {
- // 演示环境用 qa 的
- mode = DebugConfig.NET_MODE_QA;
- }
- AccountClientManager.init( sApp, mode, NetEnvironManager.OS_2C, "os2.0-launcher" );
- getTicket( new TicketInfoCallback() {
- @Override
- public void onSuccess( String ticket ) {
- SpStorage.setTicket( ticket );
- Logger.w( TAG, "request ticket success" );
- }
+ protected void asyncInitImpl(){
- @Override
- public void onFailure( int code, String msg ) {
- Logger.w( TAG, "request ticket error code = %d, msg = %s", code, msg );
- }
- } );
}
- private static void getTicket( TicketInfoCallback callback ) {
- if ( DebugConfig.isLauncher() ) {
- AccountClientManager.getTicket( callback );
- } else {
- AccountClientManager.getAppTicket( callback );
- }
- }
+// private static void initAccountSdk() {
+// int mode = DebugConfig.getNetMode();
+// if ( mode == DebugConfig.NET_MODE_DEMO ) {
+// // 演示环境用 qa 的
+// mode = DebugConfig.NET_MODE_QA;
+// }
+// AccountClientManager.init( sApp, mode, NetEnvironManager.OS_2C, "os2.0-launcher" );
+// getTicket( new TicketInfoCallback() {
+// @Override
+// public void onSuccess( String ticket ) {
+// SpStorage.setTicket( ticket );
+// Logger.w( TAG, "request ticket success" );
+// }
+//
+// @Override
+// public void onFailure( int code, String msg ) {
+// Logger.w( TAG, "request ticket error code = %d, msg = %s", code, msg );
+// }
+// } );
+// }
+//
+// private static void getTicket( TicketInfoCallback callback ) {
+// if ( DebugConfig.isLauncher() ) {
+// AccountClientManager.getTicket( callback );
+// } else {
+// AccountClientManager.getAppTicket( callback );
+// }
+// }
private static void initNetConfig() {
diff --git a/foudations/mogo-commons/src/main/java/com/mogo/commons/network/Utils.java b/foudations/mogo-commons/src/main/java/com/mogo/commons/network/Utils.java
index 21c8991b5a..f4040a23c5 100644
--- a/foudations/mogo-commons/src/main/java/com/mogo/commons/network/Utils.java
+++ b/foudations/mogo-commons/src/main/java/com/mogo/commons/network/Utils.java
@@ -7,6 +7,7 @@ import android.telephony.CellLocation;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -55,11 +56,16 @@ public class Utils {
public static final String GET = "get";
public static final String GSM_SERIAL = "gsm.serial";
+ public static final String BYD_SERIAL = "ro.serialno";
public static final String FOTA_VERSION = "ro.fota.version";
public static final String PROPERTIES = "android.os.SystemProperties";
public static String getSn() {
- return getSystemProperties( GSM_SERIAL );
+ String sn = getSystemProperties( GSM_SERIAL );
+ if ( TextUtils.isEmpty( sn ) ) {
+ sn = getSystemProperties( BYD_SERIAL );
+ }
+ return sn;
}
public static String getFotaVersion() {
diff --git a/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/MsgBody.java b/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/MsgBody.java
deleted file mode 100644
index d2ff058a25..0000000000
--- a/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/MsgBody.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.mogo.connection.socket;
-
-import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
-import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
-
-/**
- * @author congtaowang
- * @since 2019-12-31
- *
- * 描述
- */
-public class MsgBody {
-
- private int mMsgType;
-
- /**
- * 服务端分发,业务线
- */
- private int mProductLine = MogoCommon.Product.mogoBussiness_VALUE;
-
- /**
- *
- */
- private int mHeaderType = MogoConnsvr.MsgType.mogoMsgTypeDispatchSvrNoRspReq_VALUE;
-
- /**
- * 是否回执
- */
- private boolean mAck = false;
-
- /**
- * 消息ID
- */
- private final long mMsgId = System.currentTimeMillis();
-
- private Object mContent;
-
- public MsgBody msgType( int msgType ) {
- this.mMsgType = msgType;
- return this;
- }
-
- public MsgBody ack( boolean ack ) {
- this.mAck = ack;
- return this;
- }
-
- public MsgBody content( Object content ) {
- this.mContent = content;
- return this;
- }
-
- public int getMsgType() {
- return mMsgType;
- }
-
- public int getProductLine() {
- return mProductLine;
- }
-
- public int getHeaderType() {
- return mHeaderType;
- }
-
- public boolean ismAck() {
- return mAck;
- }
-
- public long getMsgId() {
- return mMsgId;
- }
-
- public Object getContent() {
- return mContent;
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 496100f81d..69d77bb862 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -57,7 +57,7 @@ MOGO_MODULE_MAIN_INDEPENDENT_VERSION = 1.2.1.17
## 工程外部模块
# 探路
-MOGO_MODULE_TANLU_VERSION=1.3.0.3-byd
+MOGO_MODULE_TANLU_VERSION=1.3.0.4-byd
# 车聊聊
CARCHATTING_VERSION=1.4.1
# 车聊聊接口
@@ -69,15 +69,15 @@ MOGO_MODULE_GUIDESHOW_PROVIDER_VERSION=1.0.2-SNAPSHOT
# 在线车辆F
MOGO_MODULE_ONLINECAR_VERSION=1.0.3.2
# v2x
-MOGO_MODULE_V2X_VERSION=1.3.0
+MOGO_MODULE_V2X_VERSION=1.3.1
# 推送
-MOGO_MODULE_PUSH_VERSION=1.1.5.6
+MOGO_MODULE_PUSH_VERSION=1.1.5.7
MOGO_MODULE_PUSH_BASE_VERSION=1.1.5.5
-MOGO_MODULE_PUSH_NOOP_VERSION=1.1.5.5
+MOGO_MODULE_PUSH_NOOP_VERSION=1.1.5.6
# 广告资源位
MOGO_MODULE_AD_CARD_VERSION=1.0.1
# 探路上报和分享模块
-TANLULIB_VERSION=1.3.0.3-byd
+TANLULIB_VERSION=1.3.0.4-byd
MOGO_MODULE_EVENT_PANEL_VERSION = 1.0.0-SNAPSHOT
MOGO_MODULE_EVENT_PANEL_NOOP_VERSION = 1.0.0-SNAPSHOT
#左侧面板模块
@@ -96,6 +96,10 @@ MOGO_MODULE_OBU_VERSION = 1.2.1.10-SNAPSHOT
MOGO_MODULE_SPLASH_VERSION = 1.0.0-SNAPSHOT
MOGO_MODULE_SPLASH_NOOP_VERSION = 1.0.0-SNAPSHOT
+# 基础服务实现:passport、socket、location
+MOGO_BASE_SERVICES_APK_VERSION = 1.0.0
+MOGO_BASE_SERVICES_SDK_VERSION = 1.0.0
+
## 产品库必备配置
applicationId=com.mogo.launcer
applicationName=IntelligentPilot
diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/AMapNaviListenerAdapter.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/AMapNaviListenerAdapter.java
index fe16b38c0e..ab14875e9e 100644
--- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/AMapNaviListenerAdapter.java
+++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/AMapNaviListenerAdapter.java
@@ -66,7 +66,7 @@ public abstract class AMapNaviListenerAdapter implements AMapNaviListener {
public void onGetNavigationText( String s ) {
mLastSpeakWord = s;
Logger.d( TAG, s );
- TTSSpeaker.getInstance().speakTTS( s );
+// TTSSpeaker.getInstance().speakTTS( s );
}
@Override
diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviClient.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviClient.java
index 82b151c0a2..963a177155 100644
--- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviClient.java
+++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviClient.java
@@ -11,6 +11,7 @@ import com.amap.api.navi.enums.AimLessMode;
import com.amap.api.navi.enums.NaviType;
import com.amap.api.navi.model.NaviLatLng;
import com.mogo.commons.AbsMogoApplication;
+import com.mogo.commons.debug.DebugConfig;
import com.mogo.commons.voice.AIAssist;
import com.mogo.map.MogoLatLng;
import com.mogo.map.impl.amap.AMapWrapper;
@@ -78,7 +79,7 @@ public class NaviClient implements IMogoNavi {
mContext = context;
mAMapNavi = AMapNavi.getInstance( context );
mAMapNavi.setEmulatorNaviSpeed( 120 );
- mAMapNavi.setUseInnerVoice( false, true );
+ mAMapNavi.setUseInnerVoice( DebugConfig.isUseCustomNavi(), true );
mAMapNaviListener = new NaviListenerAdapter( context, mAMapNavi, this );
mAimlessModeListener = new AimlessModeListenerAdapter() {
};
diff --git a/main-extensions/mogo-module-main-independent/src/main/res/values-xhdpi-1920x1000/dimens.xml b/main-extensions/mogo-module-main-independent/src/main/res/values-xhdpi-1920x1000/dimens.xml
new file mode 100644
index 0000000000..c436f9daca
--- /dev/null
+++ b/main-extensions/mogo-module-main-independent/src/main/res/values-xhdpi-1920x1000/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 635px
+ 366px
+
\ No newline at end of file
diff --git a/modules/mogo-module-apps/README.md b/modules/mogo-module-apps/README.md
new file mode 100644
index 0000000000..d1169f3461
--- /dev/null
+++ b/modules/mogo-module-apps/README.md
@@ -0,0 +1 @@
+# 应用列表 + Launcher 模式下的左侧导航按钮
\ No newline at end of file
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppFilterImpl.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppFilterImpl.java
index beb26f4b71..78e4320bbd 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppFilterImpl.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppFilterImpl.java
@@ -4,15 +4,11 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import com.mogo.module.apps.model.AppEnum;
-import com.mogo.module.apps.model.AppEnumHelper;
import com.mogo.module.common.utils.CarSeries;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* @author congtaowang
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java
index 5c7b08890a..ab5af1e04c 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java
@@ -10,12 +10,14 @@ import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.MvpFragment;
import com.mogo.module.apps.adapter.AppIndicatorAdapter;
import com.mogo.module.apps.anim.AnimWrapper;
import com.mogo.module.apps.applaunch.AppLauncher;
import com.mogo.module.apps.applaunch.BaseAppLauncher;
import com.mogo.module.apps.applaunch.InternalFunctionLauncher;
+import com.mogo.module.apps.model.AppEnum;
import com.mogo.module.apps.model.AppInfo;
import com.mogo.module.apps.model.NavigatorApps;
import com.mogo.module.apps.view.OnAiAssistClickListener;
@@ -128,7 +130,15 @@ public class AppNavigatorFragment extends MvpFragment< AppNavigatorView, AppNavi
properties.put( "appname", appLabel );
}
if ( !TextUtils.equals( "全部应用", app.getName() ) ) {
- properties.put( "appversion", CommonUtils.getVersionName( getContext(), app.getPackageName() ) );
+ if ( TextUtils.equals( "com.zhidao.music", app.getPackageName() ) ) {
+ if ( AppUtils.isAppInstalled( AbsMogoApplication.getApp(), AppEnum.KwMusic.getPkg() ) ) {
+ properties.put( "appversion", CommonUtils.getVersionName( getContext(), AppEnum.KwMusic.getPkg() ) );
+ } else if ( AppUtils.isAppInstalled( AbsMogoApplication.getApp(), AppEnum.QQMusic.getPkg() ) ) {
+ properties.put( "appversion", CommonUtils.getVersionName( getContext(), AppEnum.QQMusic.getPkg() ) );
+ }
+ } else {
+ properties.put( "appversion", CommonUtils.getVersionName( getContext(), app.getPackageName() ) );
+ }
} else {
properties.put( "appversion", CommonUtils.getVersionName( getContext() ) );
}
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLaunchFilter.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLaunchFilter.java
index a934c9895a..3bab4c03e6 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLaunchFilter.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLaunchFilter.java
@@ -14,5 +14,7 @@ public interface AppLaunchFilter {
void launch( Context context, AppInfo appInfo );
+ void launch( Context context, String pkg );
+
void destroy();
}
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLauncher.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLauncher.java
index 73c6989b9e..f148156e82 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLauncher.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/AppLauncher.java
@@ -21,15 +21,7 @@ public class AppLauncher extends BaseAppLauncher {
@Override
public void launch( Context context, AppInfo appInfo ) {
- try {
- if ( LaunchUtils.getLaunchIntentForPackage( context, appInfo.getPackageName() ) != null ) {
- AppServiceHandler.getApis().getAdasControllerApi().closeADAS();
- }
- LaunchUtils.launchByPkg( context, appInfo.getPackageName() );
- } catch ( Exception e ) {
- Logger.e( TAG, e, "error." );
- TipToast.shortTip( R.string.module_apps_str_no_app );
- }
+ launch( context, appInfo.getPackageName() );
}
@Override
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/BaseAppLauncher.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/BaseAppLauncher.java
index 7b6cadd640..2b27fb3566 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/BaseAppLauncher.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/BaseAppLauncher.java
@@ -1,5 +1,13 @@
package com.mogo.module.apps.applaunch;
+import android.content.Context;
+
+import com.mogo.module.apps.AppServiceHandler;
+import com.mogo.module.apps.R;
+import com.mogo.utils.LaunchUtils;
+import com.mogo.utils.TipToast;
+import com.mogo.utils.logger.Logger;
+
/**
* @author congtaowang
* @since 2020-02-09
@@ -8,6 +16,8 @@ package com.mogo.module.apps.applaunch;
*/
public abstract class BaseAppLauncher implements AppLaunchFilter {
+ private static final String TAG = "BaseAppLauncher";
+
private AppLaunchFilter mNext;
public AppLaunchFilter getNext() {
@@ -17,4 +27,17 @@ public abstract class BaseAppLauncher implements AppLaunchFilter {
public void setNext( AppLaunchFilter next ) {
this.mNext = next;
}
+
+ @Override
+ public void launch( Context context, String pkg ) {
+ try {
+ if ( LaunchUtils.getLaunchIntentForPackage( context, pkg ) != null ) {
+ AppServiceHandler.getApis().getAdasControllerApi().closeADAS();
+ }
+ LaunchUtils.launchByPkg( context, pkg );
+ } catch ( Exception e ) {
+ Logger.e( TAG, e, "error." );
+ TipToast.shortTip( R.string.module_apps_str_no_app );
+ }
+ }
}
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/InternalFunctionLauncher.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/InternalFunctionLauncher.java
index fa39cd2a9a..75af6c4455 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/InternalFunctionLauncher.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/applaunch/InternalFunctionLauncher.java
@@ -5,12 +5,17 @@ import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
+import com.mogo.commons.AbsMogoApplication;
import com.mogo.module.apps.AppServiceHandler;
import com.mogo.module.apps.AppsListActivity;
+import com.mogo.module.apps.R;
+import com.mogo.module.apps.model.AppEnum;
import com.mogo.module.apps.model.AppInfo;
import com.mogo.module.common.map.CustomNaviInterrupter;
+import com.mogo.utils.AppUtils;
import com.mogo.utils.LaunchUtils;
import com.mogo.utils.TipToast;
+import com.mogo.utils.logger.Logger;
/**
* @author congtaowang
@@ -32,7 +37,7 @@ public class InternalFunctionLauncher extends BaseAppLauncher {
case "com.autonavi.amapauto":
if ( CustomNaviInterrupter.getInstance().interrupt() ) {
try {
- LaunchUtils.launchByPkg( context, "com.autonavi.amapauto" );
+ launch( context, AppEnum.AUTO_NAVI.getPkg() );
} catch ( Exception e ) {
e.printStackTrace();
}
@@ -50,6 +55,23 @@ public class InternalFunctionLauncher extends BaseAppLauncher {
startActivity( context, appInfo, "com.zhidao.bluetooth.ui.MainActivity" );
}
break;
+ case "com.zhidao.music":
+ if ( AppUtils.isAppInstalled( AbsMogoApplication.getApp(), AppEnum.KwMusic.getPkg() ) ) {
+ try {
+ launch( context, AppEnum.KwMusic.getPkg() );
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ } else if ( AppUtils.isAppInstalled( AbsMogoApplication.getApp(), AppEnum.QQMusic.getPkg() ) ) {
+ try {
+ launch( context, AppEnum.QQMusic.getPkg() );
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ } else {
+ TipToast.shortTip( R.string.module_apps_str_no_app );
+ }
+ break;
default:
if ( getNext() != null ) {
getNext().launch( context, appInfo );
diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/model/NavigatorApps.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/model/NavigatorApps.java
index be2b7b2fc1..12c4c92d54 100644
--- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/model/NavigatorApps.java
+++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/model/NavigatorApps.java
@@ -16,7 +16,7 @@ public class NavigatorApps {
private static AppInfo app = new AppInfo( "高德地图", "com.autonavi.amapauto", "", 0, null, R.drawable.module_apps_ic_navigator_navi, 1 );
private static AppInfo app_ = new AppInfo( "高德地图", "com.autonavi.amapauto", "", 0, null, R.drawable.module_apps_ic_navigator_navi_disable, 1 );
// private static AppInfo app2 = new AppInfo( "音乐", "com.tencent.wecarflow", "", 0, null, R.drawable.module_apps_ic_navigator_media, 2 );
- private static AppInfo app2 = new AppInfo( "酷我音乐", "cn.kuwo.kwmusiccar", "", 0, null, R.drawable.module_apps_ic_navigator_media, 2 );
+ private static AppInfo app2 = new AppInfo( "音乐", "com.zhidao.music", "", 0, null, R.drawable.module_apps_ic_navigator_media, 2 );
private static AppInfo app3 = new AppInfo( "车聊聊", "com.zhidao.imdemo", "", 0, null, R.drawable.module_apps_ic_navigator_im, 6 );
private static AppInfo app4 = new AppInfo( "全部应用", "com.mogo.launcher.applist", "", 0, null, R.drawable.module_apps_ic_navigator_applist, 4 );
diff --git a/modules/mogo-module-apps/src/main/res/values/strings.xml b/modules/mogo-module-apps/src/main/res/values/strings.xml
index 93d46e9929..3bf6847233 100644
--- a/modules/mogo-module-apps/src/main/res/values/strings.xml
+++ b/modules/mogo-module-apps/src/main/res/values/strings.xml
@@ -18,6 +18,9 @@
- com.iflytek.inputmethod.pad
- com.nwd.tools.reboot
- com.android.car.setting
+ - com.zhidao.bootmanager
+ - com.zhidao.services
+ - com.android.settings
- com.mogo.launcher
diff --git a/modules/mogo-module-back/README.md b/modules/mogo-module-back/README.md
new file mode 100644
index 0000000000..fd719f465c
--- /dev/null
+++ b/modules/mogo-module-back/README.md
@@ -0,0 +1 @@
+# Launcher 模式下分体机F系列的返回桌面悬浮按钮 和 "返回桌面"语音指令
\ No newline at end of file
diff --git a/modules/mogo-module-common/README.md b/modules/mogo-module-common/README.md
new file mode 100644
index 0000000000..1552f28128
--- /dev/null
+++ b/modules/mogo-module-common/README.md
@@ -0,0 +1,11 @@
+# 基础框架
+
+## 基于 WindowManger.addView 方式实现的弹窗
+
+## 大而全数据定义
+
+## 地图中心点控制策略
+
+## 自研车机类型判断
+
+## 模块加载类
\ No newline at end of file
diff --git a/modules/mogo-module-extensions/README.md b/modules/mogo-module-extensions/README.md
index d056ef61b8..0c9544301a 100644
--- a/modules/mogo-module-extensions/README.md
+++ b/modules/mogo-module-extensions/README.md
@@ -1,9 +1,9 @@
# launcher头部模块
-## 小智语音
-
## 通知
## 天气
-## 时间
\ No newline at end of file
+## 时间
+
+## 入口按钮,高德SDK导航控制
\ No newline at end of file
diff --git a/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/utils/TopViewAnimHelper.java b/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/utils/TopViewAnimHelper.java
index 0d4a626e29..5c67f3141e 100644
--- a/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/utils/TopViewAnimHelper.java
+++ b/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/utils/TopViewAnimHelper.java
@@ -6,6 +6,7 @@ import android.transition.AutoTransition;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.util.ArrayMap;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
@@ -394,6 +395,11 @@ public class TopViewAnimHelper {
constraintSet.connect(naviBg.getId(), ConstraintSet.TOP,
R.id.module_entrance_id_top_motion_layout, ConstraintSet.TOP,
computeNaviMarginTop(params.height));
+
+ // 动态改变相关字体大小
+ tvNextDistance.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_textSize_small));
+ tvNextDistanceUnit.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_unit_textSize_small));
+
}
constraintSet.applyTo(topMotionLayout);
ivTurnIcon.getLayoutParams().height =
@@ -487,6 +493,9 @@ public class TopViewAnimHelper {
remainDistanceGroup.setVisibility(View.VISIBLE);
remainTimeGroup.setVisibility(View.VISIBLE);
arriveTimeGroup.setVisibility(View.VISIBLE);
+ tvNextDistance.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_textSize));
+ tvNextDistanceUnit.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_unit_textSize));
+
}
constraintSet.clone(topMotionLayout);
@@ -547,6 +556,9 @@ public class TopViewAnimHelper {
remainDistanceGroup.setVisibility(View.VISIBLE);
remainTimeGroup.setVisibility(View.VISIBLE);
arriveTimeGroup.setVisibility(View.VISIBLE);
+ tvNextDistance.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_textSize));
+ tvNextDistanceUnit.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_unit_textSize));
+
// 调整约束
constraintSet.clone(topMotionLayout);
constraintSet.clear(tvNextDistance.getId(), ConstraintSet.BOTTOM);
@@ -576,6 +588,8 @@ public class TopViewAnimHelper {
remainDistanceGroup.setVisibility(View.GONE);
remainTimeGroup.setVisibility(View.GONE);
arriveTimeGroup.setVisibility(View.GONE);
+ tvNextDistance.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_textSize_small));
+ tvNextDistanceUnit.setTextSize(TypedValue.COMPLEX_UNIT_PX,getDimen(R.dimen.module_ext_navi_info_panel_next_info_distance_unit_textSize_small));
// 调整约束
constraintSet.clone(topMotionLayout);
constraintSet.connect(tvNextDistance.getId(), ConstraintSet.BOTTOM,
@@ -655,7 +669,7 @@ public class TopViewAnimHelper {
}
private float getDimen(int resId) {
- return (int) topMotionLayout.getContext().getResources().getDimension(resId);
+ return (int) topMotionLayout.getContext().getResources().getDimensionPixelSize(resId);
}
private int computeNaviMarginTop(int height) {
diff --git a/modules/mogo-module-extensions/src/main/res/layout-xhdpi-1920x1000/include_navi_info_panle.xml b/modules/mogo-module-extensions/src/main/res/layout-xhdpi-1920x1000/include_navi_info_panle.xml
index a861e90537..9993214dcd 100644
--- a/modules/mogo-module-extensions/src/main/res/layout-xhdpi-1920x1000/include_navi_info_panle.xml
+++ b/modules/mogo-module-extensions/src/main/res/layout-xhdpi-1920x1000/include_navi_info_panle.xml
@@ -1,15 +1,16 @@
+
+ app:layout_constraintVertical_chainStyle="packed" />
+ app:layout_constraintTop_toTopOf="@+id/module_map_id_remaining_distance_notice" />
+
+ app:layout_constraintRight_toLeftOf="@+id/module_map_id_arrive_time"
+ app:layout_constraintTop_toTopOf="@id/module_map_id_navi_bg"
+ app:layout_constraintVertical_chainStyle="packed" />
+
+ app:layout_constraintTop_toTopOf="@id/module_map_id_remaining_time_notice" />
+
+ app:layout_constraintRight_toRightOf="@id/module_map_id_navi_bg"
+ app:layout_constraintTop_toTopOf="@id/module_map_id_navi_bg"
+ app:layout_constraintVertical_chainStyle="packed" />
+
+ app:layout_constraintTop_toTopOf="@+id/module_map_id_arrive_time_notice" />
+
\ No newline at end of file
diff --git a/modules/mogo-module-extensions/src/main/res/values-xhdpi-1920x1000/dimens.xml b/modules/mogo-module-extensions/src/main/res/values-xhdpi-1920x1000/dimens.xml
index 169a5f6e4e..0e3d697760 100644
--- a/modules/mogo-module-extensions/src/main/res/values-xhdpi-1920x1000/dimens.xml
+++ b/modules/mogo-module-extensions/src/main/res/values-xhdpi-1920x1000/dimens.xml
@@ -89,9 +89,11 @@
24px
40px
60px
+ 50px
12px
10px
40px
+ 30px
34px
24px
28px
diff --git a/modules/mogo-module-extensions/src/main/res/values-xhdpi/dimens.xml b/modules/mogo-module-extensions/src/main/res/values-xhdpi/dimens.xml
index 059f8fb764..b1e5bf7240 100644
--- a/modules/mogo-module-extensions/src/main/res/values-xhdpi/dimens.xml
+++ b/modules/mogo-module-extensions/src/main/res/values-xhdpi/dimens.xml
@@ -89,9 +89,11 @@
24px
40px
60px
+ 50px
12px
10px
40px
+ 30px
34px
24px
28px
diff --git a/modules/mogo-module-extensions/src/main/res/values/dimens.xml b/modules/mogo-module-extensions/src/main/res/values/dimens.xml
index a55c7a34a9..3b7a570ba8 100644
--- a/modules/mogo-module-extensions/src/main/res/values/dimens.xml
+++ b/modules/mogo-module-extensions/src/main/res/values/dimens.xml
@@ -91,9 +91,11 @@
13px
20px
32px
+ 32px
7px
5px
22px
+ 22px
18px
24px
diff --git a/modules/mogo-module-gps-simulator-debug/README.md b/modules/mogo-module-gps-simulator-debug/README.md
new file mode 100644
index 0000000000..3266bdbaae
--- /dev/null
+++ b/modules/mogo-module-gps-simulator-debug/README.md
@@ -0,0 +1 @@
+# GPS 轨迹模拟接口 Debug 实现
diff --git a/modules/mogo-module-gps-simulator-noop/README.md b/modules/mogo-module-gps-simulator-noop/README.md
new file mode 100644
index 0000000000..6478f3ac12
--- /dev/null
+++ b/modules/mogo-module-gps-simulator-noop/README.md
@@ -0,0 +1 @@
+# GPS 轨迹模拟接口 Release 实现
diff --git a/modules/mogo-module-gps-simulator/README.md b/modules/mogo-module-gps-simulator/README.md
new file mode 100644
index 0000000000..d396740f2b
--- /dev/null
+++ b/modules/mogo-module-gps-simulator/README.md
@@ -0,0 +1,5 @@
+# GPS 轨迹模拟接口抽象
+
+## 常量定义
+
+## 接口
diff --git a/modules/mogo-module-main/README.md b/modules/mogo-module-main/README.md
new file mode 100644
index 0000000000..e7ab07ca99
--- /dev/null
+++ b/modules/mogo-module-main/README.md
@@ -0,0 +1,18 @@
+# 主模块
+
+## 子模块加载管理
+
+## 加载地图
+
+## 事件分发
+
+## service 后台服务
+
+开启定位、加载基础服务模块:v2x、刷新策略、事件上报模块、初始化 ADAS 服务
+
+## 应用内浮窗管理:车聊聊、音乐等
+
+## 顶部弹窗管理
+
+## scheme 跳转管理
+
diff --git a/modules/mogo-module-main/build.gradle b/modules/mogo-module-main/build.gradle
index 40f32d957a..01d390ad2f 100644
--- a/modules/mogo-module-main/build.gradle
+++ b/modules/mogo-module-main/build.gradle
@@ -52,7 +52,6 @@ dependencies {
api rootProject.ext.dependencies.mogoservice
api rootProject.ext.dependencies.moduleservice
api rootProject.ext.dependencies.moduleapps
- api rootProject.ext.dependencies.mogoconnection
api rootProject.ext.dependencies.moduleextensions
api rootProject.ext.dependencies.mogomoduleback
} else {
@@ -64,7 +63,6 @@ dependencies {
api project(':services:mogo-service-api')
api project(':services:mogo-service')
api project(':modules:mogo-module-apps')
- api project(':foudations:mogo-connection')
api project(':modules:mogo-module-extensions')
api project(':modules:mogo-module-back')
}
diff --git a/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml b/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml
index c3a6b4463d..bcb2744c24 100644
--- a/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml
+++ b/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml
@@ -43,12 +43,10 @@
+ android:layout_marginLeft="@dimen/module_main_id_entrance_fragment_container_marginLeft"
+ android:padding="@dimen/module_main_entrance_fragment_container_padding" />
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-splash/src/main/res/drawable/byd_enter_btn_bg.xml b/modules/mogo-module-splash/src/main/res/drawable/byd_enter_btn_bg.xml
new file mode 100644
index 0000000000..e34b2f6181
--- /dev/null
+++ b/modules/mogo-module-splash/src/main/res/drawable/byd_enter_btn_bg.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mogo-module-splash/src/main/res/drawable-xhdpi/binli.jpg b/modules/mogo-module-splash/src/main/res/drawable/module_byd_splash.png
similarity index 100%
rename from modules/mogo-module-splash/src/main/res/drawable-xhdpi/binli.jpg
rename to modules/mogo-module-splash/src/main/res/drawable/module_byd_splash.png
diff --git a/modules/mogo-module-splash/src/main/res/layout/fragment_byd_splash.xml b/modules/mogo-module-splash/src/main/res/layout/fragment_byd_splash.xml
index 45207fa003..f7bb689995 100644
--- a/modules/mogo-module-splash/src/main/res/layout/fragment_byd_splash.xml
+++ b/modules/mogo-module-splash/src/main/res/layout/fragment_byd_splash.xml
@@ -2,32 +2,37 @@
+ android:layout_height="match_parent">
+
+
+ app:layout_constraintStart_toStartOf="parent"/>
diff --git a/modules/mogo-module-v2x/.gitignore b/modules/mogo-module-v2x/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/modules/mogo-module-v2x/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/modules/mogo-module-v2x/README.md b/modules/mogo-module-v2x/README.md
new file mode 100644
index 0000000000..aacceabed4
--- /dev/null
+++ b/modules/mogo-module-v2x/README.md
@@ -0,0 +1,25 @@
+#### 项目介绍
+本项目是V2X模块,必须依附于Launcher进行集成使用,无法单独使用,且需要车机安装Autopilot(ADAS)一起使用。
+
+#### 项目结构
+- adapter --- 展示视图适配
+- alarm --- 提醒计算
+- entity --- 数据实体
+- listener --- Socket监听
+- manager --- 管理工具,绘制marker,绘制连接线,记录状态
+- marker --- 地图marker视图适配
+- network --- 网络请求
+- scenario --- 场景,可以简单的理解为每一种弹窗是一种场景
+ - scene
+ - animation --- 场景动画 H5 推送下来的
+ - fatigue --- 疲劳驾驶
+ - help --- 自车故障求助
+ - livecar --- 直播场景,H5推送的和道路事件预警的
+ - park --- 违章停车
+ - push --- 推送的演示场景,取快递、政府公告、顺风车、行人点赞
+ - road --- 道路事件预警
+ - seek --- 他人故障求助预警
+ - test --- 测试页面,一堆按钮,自己点击触发以上场景
+- utils --- 工具类
+- view --- 自定义视图
+- voice --- 语音注册
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/build.gradle b/modules/mogo-module-v2x/build.gradle
new file mode 100644
index 0000000000..3b68184f18
--- /dev/null
+++ b/modules/mogo-module-v2x/build.gradle
@@ -0,0 +1,74 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.alibaba.arouter'
+apply plugin: 'android-aspectjx'
+
+android {
+ compileSdkVersion rootProject.ext.android.compileSdkVersion
+ 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()]
+ }
+ }
+ ndk {
+ abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'com.tencent.liteavsdk:LiteAVSDK_Smart:7.2.8927'
+ implementation 'ch.hsr:geohash:1.4.0'
+ implementation rootProject.ext.dependencies.flexbox
+ implementation "com.zhidao.auto.lib:sqlite:0.1.1"
+
+ compileOnly rootProject.ext.dependencies.kotlinstdlibjdk7
+ compileOnly rootProject.ext.dependencies.androidxccorektx
+ compileOnly rootProject.ext.dependencies.androidxrecyclerview
+
+ compileOnly rootProject.ext.dependencies.mogomap
+ compileOnly rootProject.ext.dependencies.mogoutils
+ compileOnly rootProject.ext.dependencies.mogocommons
+ compileOnly rootProject.ext.dependencies.mogoservice
+ compileOnly rootProject.ext.dependencies.mogoserviceapi
+ compileOnly rootProject.ext.dependencies.modulecommon
+ compileOnly rootProject.ext.dependencies.moduleservice
+ compileOnly rootProject.ext.dependencies.androidxappcompat
+ compileOnly rootProject.ext.dependencies.androidxconstraintlayout
+ compileOnly rootProject.ext.dependencies.arouter
+ compileOnly rootProject.ext.dependencies.carcallprovider
+ compileOnly rootProject.ext.dependencies.carcall
+
+ annotationProcessor rootProject.ext.dependencies.aroutercompiler
+
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
+
+apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
diff --git a/modules/mogo-module-v2x/consumer-rules.pro b/modules/mogo-module-v2x/consumer-rules.pro
new file mode 100644
index 0000000000..4a277db73d
--- /dev/null
+++ b/modules/mogo-module-v2x/consumer-rules.pro
@@ -0,0 +1,2 @@
+-keep class com.tencent.** { *; }
+-keep com.mogo.module.v2x.entity.** { *; }
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/gradle.properties b/modules/mogo-module-v2x/gradle.properties
new file mode 100644
index 0000000000..2cb3dc2a8a
--- /dev/null
+++ b/modules/mogo-module-v2x/gradle.properties
@@ -0,0 +1,3 @@
+GROUP=com.mogo.module
+POM_ARTIFACT_ID=module-v2x
+VERSION_CODE=1
diff --git a/modules/mogo-module-v2x/proguard-rules.pro b/modules/mogo-module-v2x/proguard-rules.pro
new file mode 100644
index 0000000000..355c19a070
--- /dev/null
+++ b/modules/mogo-module-v2x/proguard-rules.pro
@@ -0,0 +1,23 @@
+# 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
+-keep class com.tencent.* { *; }
+-keep class com.mogo.module.v2x.entity.* { *; }
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/androidTest/java/com/mogo/module/blackbox/ExampleInstrumentedTest.java b/modules/mogo-module-v2x/src/androidTest/java/com/mogo/module/blackbox/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000..7fd2f97597
--- /dev/null
+++ b/modules/mogo-module-v2x/src/androidTest/java/com/mogo/module/blackbox/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.mogo.module.blackbox;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.mogo.module.blackbox.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/AndroidManifest.xml b/modules/mogo-module-v2x/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..158659eecc
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/AndroidManifest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/MoGoV2XServicePaths.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/MoGoV2XServicePaths.java
new file mode 100644
index 0000000000..20c8dde883
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/MoGoV2XServicePaths.java
@@ -0,0 +1,34 @@
+package com.mogo.module.v2x;
+
+import androidx.annotation.Keep;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 7:35 PM
+ * desc : 对外服务模块路径
+ * version: 1.0
+ * 使用方式:
+ * Arouter.getInstance().path("").navigate()
+ */
+@Keep
+public class MoGoV2XServicePaths {
+ /**
+ * V2X 状态管理
+ */
+ @Keep
+ public static final String PATH_V2X_STATUS_MANAGER = "/v2xStatusManager/api";
+
+ /**
+ * V2X 道路事件POI点
+ */
+ @Keep
+ public static final String PATH_V2X_MARKER_MANAGER = "/v2xMarkerManager/api";
+
+ /**
+ * V2X 道路事件与车辆的连接线
+ */
+ @Keep
+ public static final String PATH_V2X_POLYLINE_MANAGER = "/v2xPolylineManager/api";
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XConst.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XConst.java
new file mode 100644
index 0000000000..270da46d61
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XConst.java
@@ -0,0 +1,107 @@
+package com.mogo.module.v2x;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-2114:10
+ * desc : V2X使用到的常量
+ * version: 1.0
+ */
+public class V2XConst {
+ /**
+ * 类型
+ */
+ public static final String MODULE_NAME = "V2X_UI";
+ /**
+ * V2X模块地址
+ */
+ public static final String PATH_V2X_UI = "/v2x/ui";
+ public static final String SEEK_HELP_TIME = "seek_help_time";
+
+ /**
+ * V2X 场景广播 Action
+ */
+ public static final String BROADCAST_SCENE_HANDLER_ACTION = "com.v2x.scene_handler_broadcast";
+ public static final String BROADCAST_SCENE_EXTRA_KEY = "V2XMessageEntity";
+
+ public static final String BROADCAST_SCENE_ACTION = "com.v2x.scene_local_broadcast";
+
+ public static final String V2X_ACC_ON_TIME_STR = "v2x_acc_on_time_str";
+ public static final String V2X_ACC_OFF_TIME_STR = "v2x_acc_off_time_str";
+ public static final String V2X_STRATEGY_PUSH = "v2x_strategy_push";
+
+ public static final int STATE_ERROR = -1;
+ public static final int STATE_IDLE = 0;
+ public static final int STATE_PREPARING = 1;
+ public static final int STATE_PREPARED = 2;
+ public static final int STATE_PLAYING = 3;
+ public static final int STATE_PAUSED = 4;
+ public static final int STATE_PLAYBACK_COMPLETED = 5;
+ public static final int STATE_SEEKING = 6;
+
+ /**
+ * V2X 埋点
+ */
+ public static final String V2X_ROAD_SHOW = "v2x_road_show";
+ public static final String V2X_ROAD_EVET = "v2x_road_event";
+ /**
+ * V2X 道路事件操作类型
+ */
+ public static final String V2X_ROAD_ZAN = "1";
+ public static final String V2X_ROAD_CHAT = "2";
+ public static final String V2X_ROAD_VIDEO = "3";
+ public static final String V2X_ROAD_NAVI = "4";
+ public static final String V2X_ROAD_REPORT_RIGHT = "5";
+ public static final String V2X_ROAD_REPORT_ERROR = "6";
+
+ /**
+ * V2X 地图上发出警告的POI
+ */
+ public static final String V2X_ILLEGAL_PARK_POI = "V2X_ILLEGAL_PARK_POI";
+
+ /**
+ * V2X 地图上发出警告的POI
+ */
+ public static final String V2X_EVENT_ALARM_POI = "V2X_EVENT_ALARM_POI";
+
+ /**
+ * V2X 探路数据
+ */
+ public static final String V2X_CARD_TYPE_ROAD_CONDITION = "V2X_CARD_TYPE_ROAD_CONDITION";
+
+ /**
+ * V2X 用户数据
+ */
+ public static final String V2X_CARD_TYPE_USER_DATA = "V2X_CARD_TYPE_USER_DATA";
+
+ /**
+ * V2X 新鲜事
+ */
+ public static final String V2X_CARD_TYPE_NOVELTY = "V2X_CARD_TYPE_NOVELTY";
+
+ /**
+ * V2X 特殊车辆
+ */
+ public static final String V2X_MARKER_SPECIAL_CAR = "V2X_MARKER_SPECIAL_CAR";
+
+ /**
+ * V2X 可直播车辆
+ */
+ public static final String V2X_MARKER_LIVE_CAR = "V2X_MARKER_LIVE_CAR";
+
+ /**
+ * V2X 取快递
+ */
+ public static final String V2X_MARKER_EXPRESS = "V2X_MARKER_EXPRESS";
+
+ /**
+ * V2X 顺风车
+ */
+ public static final String V2X_MARKER_TAXI = "V2X_MARKER_TAXI";
+
+ /**
+ * V2X 政府推送消息
+ */
+ public static final String V2X_MARKER_GOVERNMENT = "V2X_MARKER_GOVERNMENT";
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XDemoManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XDemoManager.java
new file mode 100644
index 0000000000..212cde2ea7
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XDemoManager.java
@@ -0,0 +1,139 @@
+package com.mogo.module.v2x;
+
+import android.content.Intent;
+import android.text.TextUtils;
+
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerUserInfo;
+import com.mogo.module.v2x.entity.net.V2XDemoUserInfoRes;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.utils.logger.Logger;
+
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/28 12:24 PM
+ * desc : 演示DEMO管理
+ * version: 1.0
+ */
+public class V2XDemoManager {
+ private List userListBeanList;
+ private V2XDemoUserInfoRes.ResultBean.UserListBean mV2XDemoUserInfoEntity1;
+ private V2XDemoUserInfoRes.ResultBean.UserListBean mV2XDemoUserInfoEntity2;
+ private V2XDemoUserInfoRes.ResultBean.UserListBean mV2XDemoUserInfoEntity3;
+ private static V2XDemoManager mV2XDemoManager;
+
+ private V2XDemoManager() {
+ }
+
+ public static V2XDemoManager getInstance() {
+ if (mV2XDemoManager == null) {
+ synchronized (V2XDemoManager.class) {
+ if (mV2XDemoManager == null) {
+ mV2XDemoManager = new V2XDemoManager();
+ }
+ }
+ }
+ return mV2XDemoManager;
+ }
+
+ public void initData() {
+ // 获取演示车辆信息
+ V2XServiceManager
+ .getV2XRefreshModel()
+ .getMockUserInfos(new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(V2XDemoUserInfoRes result) {
+ userListBeanList = result.getResult().getUserList();
+ Logger.w(MODULE_NAME, "V2X演示用户数据:" + userListBeanList);
+
+ for (V2XDemoUserInfoRes.ResultBean.UserListBean userListBean : userListBeanList) {
+ switch (userListBean.getSceneType()) {
+ case "1":
+ mV2XDemoUserInfoEntity1 = userListBean;
+ break;
+ case "2":
+ mV2XDemoUserInfoEntity2 = userListBean;
+ break;
+ case "3":
+ mV2XDemoUserInfoEntity3 = userListBean;
+ break;
+ }
+ }
+
+ // 呼叫前方车辆
+ V2XVoiceManager.INSTANCE.registerWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_FRONT_CAR,
+ (String command, Intent intent) -> {
+ String dataStr = intent.getStringExtra("data");
+ Logger.w(MODULE_NAME, "mData。。。。" + dataStr);
+ if (!TextUtils.isEmpty(dataStr)) {
+ if (dataStr.contains("address")) {
+ roadCallChart(mV2XDemoUserInfoEntity2);
+ }
+ } else {
+ roadCallChart(mV2XDemoUserInfoEntity1);
+ }
+ }
+ );
+ }
+
+ @Override
+ public void onFail(String msg) {
+
+ }
+ });
+ }
+
+ public void release() {
+ // 呼叫前方车辆
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_FRONT_CAR);
+ }
+
+
+ /**
+ * 打电话
+ */
+ private void roadCallChart(V2XDemoUserInfoRes.ResultBean.UserListBean mV2XDemoUserInfoEntity) {
+ Logger.w(MODULE_NAME, "正在拨打电话。。。。" + mV2XDemoUserInfoEntity);
+
+ try {
+ if (mV2XDemoUserInfoEntity != null) {
+ MarkerUserInfo mUserInfo = new MarkerUserInfo();
+ MarkerLocation location = new MarkerLocation();
+ location.setLon(mV2XDemoUserInfoEntity.getLocation().getLon());
+ location.setLat(mV2XDemoUserInfoEntity.getLocation().getLat());
+ mUserInfo.setSn(mV2XDemoUserInfoEntity.getUserInfo().getSn());
+ mUserInfo.setUserHead(mV2XDemoUserInfoEntity.getUserInfo().getUserHead());
+ mUserInfo.setUserName(mV2XDemoUserInfoEntity.getUserInfo().getUserName());
+ mUserInfo.setGender(mV2XDemoUserInfoEntity.getUserInfo().getGender());
+ mUserInfo.setAge(mV2XDemoUserInfoEntity.getUserInfo().getAge());
+ ChartingUtil.callChatting(mUserInfo, location);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 1-拨打前方车辆,
+ public V2XDemoUserInfoRes.ResultBean.UserListBean getV2XDemoUserInfoEntity1() {
+ return mV2XDemoUserInfoEntity1;
+ }
+
+ // 2-拨打中关村附近好友,
+ public V2XDemoUserInfoRes.ResultBean.UserListBean getV2XDemoUserInfoEntity2() {
+ return mV2XDemoUserInfoEntity2;
+ }
+
+ // 3-点击地图图标拨打电话
+ public V2XDemoUserInfoRes.ResultBean.UserListBean getV2XDemoUserInfoEntity3() {
+ return mV2XDemoUserInfoEntity3;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XMarkerService.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XMarkerService.java
new file mode 100644
index 0000000000..69497f597a
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XMarkerService.java
@@ -0,0 +1,108 @@
+package com.mogo.module.v2x;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.module.v2x.listener.V2XLocationListener;
+import com.mogo.module.v2x.network.V2XRefreshModel;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/6 5:37 PM
+ * desc :
+ * version: 1.0
+ */
+public class V2XMarkerService {
+ private final String TAG = "V2XMarkerService";
+
+ // 一分钟获取一次最新的路况信息
+ private final int refreshTime = 60_000;
+ private static V2XMarkerService mV2XMarkerService;
+
+ private V2XRefreshModel mV2XRefreshModel;
+ private Handler refreshHandler;
+ private Runnable refreshRunnable;
+
+ public synchronized static V2XMarkerService getInstance(Context context) {
+ if (mV2XMarkerService == null) {
+ mV2XMarkerService = new V2XMarkerService();
+ mV2XMarkerService.init(context);
+ }
+ return mV2XMarkerService;
+ }
+
+ private void init(Context context) {
+ mV2XRefreshModel = V2XRefreshModel.getInstance(context);
+ }
+
+ public V2XRefreshModel getV2XRefreshModel() {
+ return mV2XRefreshModel;
+ }
+
+ public void refreshMarkerData(MogoLocation location) {
+ try {
+ if (mV2XRefreshModel != null && location != null) {
+ //Logger.d(MODULE_NAME, "V2X道路事件:执行气泡刷新操作。");
+ // 获取目前最新的周边的poi点
+ mV2XRefreshModel.querySnapshotAsync(
+ new MogoLatLng(location.getLatitude(), location.getLongitude()),
+ (int) getMapCameraFactWidth(),
+ 999);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 地图视图对应的实际宽度
+ */
+ private float getMapCameraFactWidth() {
+ return 1_000;
+ }
+
+ /**
+ * 关闭自动刷新
+ */
+ public void stopAutoRefresh() {
+ Logger.w(MODULE_NAME, "V2X道路事件:关闭V2X地图气泡自动刷新。");
+ V2XServiceManager
+ .getMogoRegisterCenter()
+ .unregisterMogoLocationListener(MODULE_NAME);
+
+ if (refreshHandler != null) {
+ refreshHandler.removeCallbacks(refreshRunnable);
+ }
+ refreshRunnable = null;
+ }
+
+ /**
+ * 开始刷新
+ */
+ public void startAutoRefresh() {
+ // 设置地图定位监听
+ V2XServiceManager.getMogoRegisterCenter()
+ .registerMogoLocationListener(MODULE_NAME, V2XLocationListener.getInstance());
+
+ Logger.d(MODULE_NAME, "V2X道路事件:开启V2X地图气泡自动绘制。");
+ if (refreshHandler == null) {
+ refreshHandler = new Handler();
+ }
+ if (refreshRunnable == null) {
+ refreshRunnable = new Runnable() {
+ @Override
+ public void run() {
+ refreshMarkerData(V2XLocationListener.getInstance().getLastCarLocation());
+ refreshHandler.postDelayed(this, refreshTime);
+ }
+ };
+ }
+ refreshHandler.post(refreshRunnable);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XModuleProvider.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XModuleProvider.java
new file mode 100644
index 0000000000..fd3e901346
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XModuleProvider.java
@@ -0,0 +1,294 @@
+package com.mogo.module.v2x;
+
+import android.content.Context;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.mogo.map.listener.IMogoMapListener;
+import com.mogo.map.location.IMogoLocationListener;
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.IMogoMarkerClickListener;
+import com.mogo.map.navi.IMogoNaviListener;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.service.ServiceConst;
+import com.mogo.module.v2x.entity.net.V2XSeekHelpRes;
+import com.mogo.module.v2x.entity.net.V2XStrategyPushRes;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.receiver.SceneBroadcastReceiver;
+import com.mogo.module.v2x.scenario.impl.V2XScenarioManager;
+import com.mogo.module.v2x.scenario.scene.park.V2XIllegalParkScenario;
+import com.mogo.module.v2x.scenario.scene.park.V2XIllegalParkWindow;
+import com.mogo.module.v2x.scenario.scene.test.V2XTestConsoleWindow;
+import com.mogo.module.v2x.utils.FatigueDrivingUtils;
+import com.mogo.module.v2x.utils.TimeUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.module.IMogoModuleLifecycle;
+import com.mogo.service.module.IMogoModuleProvider;
+import com.mogo.service.module.ModuleType;
+import com.mogo.service.statusmanager.IMogoStatusChangedListener;
+import com.mogo.service.statusmanager.StatusDescriptor;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.network.utils.GsonUtil;
+import com.mogo.utils.storage.SharedPrefsMgr;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-2114:03
+ * desc : V2X的管理
+ * version: 2.0
+ */
+@Route(path = V2XConst.PATH_V2X_UI)
+public class V2XModuleProvider implements
+ IMogoModuleProvider,
+ IMogoStatusChangedListener {
+ private final String TAG = "V2XMocduleProvider";
+
+ private Context mContext;
+
+ @Override
+ public Fragment createFragment(Context context, Bundle data) {
+ return null;
+ }
+
+ @Override
+ public View createView(Context context) {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public String getModuleName() {
+ return ServiceConst.TYPE;
+ }
+
+ @Override
+ public IMogoModuleLifecycle getCardLifecycle() {
+ return null;
+ }
+
+ @Override
+ public IMogoMapListener getMapListener() {
+ return null;
+ }
+
+ @Override
+ public int getType() {
+ return ModuleType.TYPE_SERVICE;
+ }
+
+ @Override
+ public IMogoNaviListener getNaviListener() {
+ return null;
+ }
+
+ @Override
+ public IMogoLocationListener getLocationListener() {
+ return null;
+ }
+
+ @Override
+ public IMogoMarkerClickListener getMarkerClickListener() {
+ return null;
+ }
+
+ @Override
+ public String getAppPackage() {
+ return null;
+ }
+
+ @Override
+ public String getAppName() {
+ return null;
+ }
+
+ @Override
+ public void init(Context context) {
+ Logger.e(MODULE_NAME, "V2X模块初始化。。。。");
+ mContext = context;
+
+ V2XUtils.init(context);
+ V2XServiceManager.init(context);
+ initVoice(context);
+ handleAdas();
+ initData();
+
+ // 注册广播接收场景弹窗使用的
+ SceneBroadcastReceiver localReceiver = new SceneBroadcastReceiver();
+ LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ localBroadcastManager.registerReceiver(localReceiver, intentFilter);
+
+ // TODO 这是测试页面
+ V2XServiceManager
+ .getIMogoWindowManager()
+ .addView(new V2XTestConsoleWindow(context), 0, 0, false);
+ }
+
+ private void initVoice(Context context) {
+ V2XVoiceManager.INSTANCE.init(context);
+ }
+
+ private void initData() {
+ //初始化获得自车求助状态
+ initCarForHelpStatus();
+
+ try {
+ // 查询ACC状态
+ SharedPrefsMgr.getInstance(V2XUtils.getApp()).putBoolean("descriptor_ACC_STATUS", isAccOn());
+ if (isAccOn()) {
+ // 记录开机时间
+ FatigueDrivingUtils.refreshAccOnTime();
+ initCarForHelpStatus();
+ // 刷新配置文件
+ refreshStrategyConfig();
+ } else {
+ // 记录关机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_OFF_TIME_STR, TimeUtils.getNowString());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // 刷新配置文件
+ refreshStrategyConfig();
+
+ // 响应违章停车的POI点击
+ V2XServiceManager
+ .getMogoRegisterCenter()
+ .registerMogoMarkerClickListener(V2XConst.MODULE_NAME,
+ new IMogoMarkerClickListener() {
+ @Override
+ public boolean onMarkerClicked(IMogoMarker marker) {
+ try {
+ MarkerExploreWay markerExploreWay =
+ (MarkerExploreWay) ((MarkerShowEntity) marker.getObject()).getBindObj();
+ Logger.d(V2XConst.MODULE_NAME,
+ "V2X===违章停车:onMarkerClicked=" + markerExploreWay);
+
+ ((V2XIllegalParkWindow) V2XIllegalParkScenario.getInstance()
+ .getV2XWindow())
+ .show(markerExploreWay, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+ });
+ }
+
+ private void refreshStrategyConfig() {
+ // 获取疲劳驾驶的配置
+ V2XServiceManager
+ .getV2XRefreshModel()
+ .getStrategyPush(new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(V2XStrategyPushRes result) {
+ Logger.w(MODULE_NAME, "V2X疲劳驾驶配置数据更新:" + GsonUtil.jsonFromObject(result));
+ V2XStrategyPushRes.ResultBean resultBean = result.getResult();
+ if (resultBean != null) {
+ // 更新本地的v2x提醒策略
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_STRATEGY_PUSH, GsonUtil.jsonFromObject(resultBean));
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+
+ }
+ });
+ }
+
+ private void handleAdas() {
+ V2XServiceManager.getMoGoStatusManager()
+ .registerStatusChangedListener(MODULE_NAME, StatusDescriptor.ACC_STATUS, this);
+ V2XServiceManager.getMoGoStatusManager()
+ .registerStatusChangedListener(MODULE_NAME, StatusDescriptor.SEEK_HELPING, this);
+
+ // 注册V2X场景Socket
+ V2XServiceManager.getV2XSocketManager().registerSocketMessage();
+ // 开启自动刷新
+ V2XServiceManager.getV2XMarkerService().startAutoRefresh();
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ V2XServiceManager.getMapUIController().recoverLockMode();
+ }
+
+ private void handleSeekHelp(boolean isTrue) {
+ V2XMessageEntity entity = new V2XMessageEntity<>();
+ entity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_CAR_FOR_HELP);
+ entity.setContent(isTrue);
+ V2XScenarioManager.getInstance().handlerMessage(entity);
+ }
+
+ @Override
+ public void onStatusChanged(StatusDescriptor descriptor, boolean isTrue) {
+ Logger.d(MODULE_NAME, "状态发生改变\ndescriptor:" + descriptor + "\nisTrue:" + isTrue);
+ // 记录状态更改
+ SharedPrefsMgr.getInstance(V2XUtils.getApp()).putBoolean("descriptor_" + descriptor, isTrue);
+ if (descriptor == StatusDescriptor.ACC_STATUS) {
+ if (isTrue) {
+ // 记录开机时间
+ FatigueDrivingUtils.refreshAccOnTime();
+ initCarForHelpStatus();
+ } else {
+ // 记录关机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_OFF_TIME_STR, TimeUtils.getNowString());
+ }
+ } else if (descriptor == StatusDescriptor.SEEK_HELPING) {
+ handleSeekHelp(isTrue);
+ }
+ }
+
+ public boolean isAccOn() {
+ int accState = Settings.System.getInt(mContext.getContentResolver(), "mcu_state", -0x02);
+ Logger.d(MODULE_NAME, "状态发生改变\ndescriptor:ACC_STSTUS" + "\nisTrue:" + accState);
+ return accState == 1;
+ }
+
+ private void initCarForHelpStatus() {
+ //本地查询是否超时
+ V2XServiceManager.getV2XRefreshModel().getHelpSignal(new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(V2XSeekHelpRes result) {
+ if (result != null) {
+ V2XSeekHelpRes.ResultBean resultBean = result.getResult();
+ if (resultBean != null) {
+ int vehicleType = resultBean.getVehicleType();
+ //故障车
+ if (vehicleType == 4) {
+ if (!V2XServiceManager.getMoGoStatusManager().isSeekHelping()) {
+ handleSeekHelp(true);
+ V2XServiceManager.getMoGoStatusManager().setSeekHelping(MODULE_NAME, true);
+ }
+ } else {
+ if (V2XServiceManager.getMoGoStatusManager().isSeekHelping()) {
+ handleSeekHelp(false);
+ V2XServiceManager.getMoGoStatusManager().setSeekHelping(MODULE_NAME, false);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+
+ }
+ });
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XServiceManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XServiceManager.java
new file mode 100644
index 0000000000..621b7bd291
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XServiceManager.java
@@ -0,0 +1,246 @@
+package com.mogo.module.v2x;
+
+import android.content.Context;
+
+import com.alibaba.android.arouter.launcher.ARouter;
+import com.mogo.map.location.IMogoLocationClient;
+import com.mogo.map.marker.IMogoMarkerManager;
+import com.mogo.map.navi.IMogoNavi;
+import com.mogo.map.overlay.IMogoOverlayManager;
+import com.mogo.map.search.geo.IMogoGeoSearch;
+import com.mogo.map.uicontroller.IMogoMapUIController;
+import com.mogo.module.carchattingprovider.ICarsChattingProvider;
+import com.mogo.module.v2x.alarm.V2XCalculateServer;
+import com.mogo.module.v2x.network.V2XRefreshModel;
+import com.mogo.module.v2x.manager.IMoGoV2XMarkerManager;
+import com.mogo.module.v2x.manager.IMoGoV2XPolylineManager;
+import com.mogo.module.v2x.manager.IMoGoV2XStatusManager;
+import com.mogo.service.IMogoServiceApis;
+import com.mogo.service.MogoServicePaths;
+import com.mogo.service.adas.IMogoADASController;
+import com.mogo.service.analytics.IMogoAnalytics;
+import com.mogo.service.connection.IMogoSocketManager;
+import com.mogo.service.entrance.IMogoEntranceButtonController;
+import com.mogo.service.imageloader.IMogoImageloader;
+import com.mogo.service.intent.IMogoIntentManager;
+import com.mogo.service.map.IMogoMapService;
+import com.mogo.service.module.IMogoActionManager;
+import com.mogo.service.module.IMogoMarkerService;
+import com.mogo.service.module.IMogoRegisterCenter;
+import com.mogo.service.module.IMogoSearchManager;
+import com.mogo.service.statusmanager.IMogoStatusManager;
+import com.mogo.service.strategy.IMogoRefreshStrategyController;
+import com.mogo.service.windowview.IMogoTopViewManager;
+import com.mogo.service.windowview.IMogoWindowManager;
+import com.zhidao.carchattingprovider.CallChattingProviderConstant;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-2114:01
+ * desc : V2X 服务
+ * version: 1.0
+ */
+public class V2XServiceManager {
+ private static final String TAG = "V2XServiceManager";
+ private static Context mContext;
+ private static IMogoServiceApis mMogoServiceApis;
+
+ private static IMogoMapService mMapService;
+ private static IMogoMarkerManager mMarkerManager;
+ private static IMogoNavi mNavi;
+ private static IMogoMapUIController mMapUIController;
+ private static IMogoLocationClient mMogoLocationClient;
+ private static IMogoGeoSearch mIMogoGeoSearch;
+ private static IMogoSearchManager mIMogoSearchManager;
+
+ private static IMogoTopViewManager mMogoTopViewManager;
+ private static IMogoStatusManager mMogoStatusManager;
+ private static IMogoWindowManager mIMogoWindowManager;
+ private static IMogoImageloader mImageLoader;
+ private static IMogoSocketManager mMogoSocketManager;
+ private static IMogoAnalytics mMogoAnalytics;
+ private static IMogoOverlayManager mMogoOverlayManager;
+ private static IMogoRegisterCenter mMogoRegisterCenter;
+ private static IMogoRefreshStrategyController mIMogoRefreshStrategyController;
+ private static IMogoMarkerService mIMogoMarkerService;
+
+ private static IMogoActionManager mMogoActionManager;
+ private static ICarsChattingProvider mCarsChattingProvider;
+ private static IMogoADASController mIMogoADASController;
+ private static IMogoIntentManager mMogoIntentManager;
+ private static IMogoEntranceButtonController mMogoEntranceButtonController;
+
+ private static V2XRefreshModel mV2XRefreshModel;
+ private static V2XMarkerService mV2XMarkerService;
+ private static V2XStatusManager mV2XStatusManager;
+ private static V2XSocketManager mV2XSocketManager;
+ private static V2XCalculateServer mV2XCalculateServer;
+
+
+ // 下面的是重构后的代码,建议
+ private static IMoGoV2XMarkerManager moGoV2XMarkerManager;
+ private static IMoGoV2XPolylineManager moGoV2XPolylineManager;
+ private static IMoGoV2XStatusManager moGoV2XStatusManager;
+
+
+ public static void init(final Context context) {
+ mContext = context;
+ mMogoServiceApis = (IMogoServiceApis) ARouter.getInstance().build(MogoServicePaths.PATH_SERVICE_APIS).navigation(context);
+
+ mMapService = mMogoServiceApis.getMapServiceApi();
+ mImageLoader = mMogoServiceApis.getImageLoaderApi();
+ mMogoStatusManager = mMogoServiceApis.getStatusManagerApi();
+ mMogoSocketManager = mMogoServiceApis.getSocketManagerApi(context);
+ mMogoAnalytics = mMogoServiceApis.getAnalyticsApi();
+ mIMogoWindowManager = mMogoServiceApis.getWindowManagerApi();
+ mMogoRegisterCenter = mMogoServiceApis.getRegisterCenterApi();
+ mIMogoRefreshStrategyController = mMogoServiceApis.getRefreshStrategyControllerApi();
+ mIMogoADASController = mMogoServiceApis.getAdasControllerApi();
+ mMogoEntranceButtonController = mMogoServiceApis.getEntranceButtonController();
+ mMogoActionManager = mMogoServiceApis.getActionManagerApi();
+ mMogoTopViewManager = mMogoServiceApis.getTopViewManager();
+ mIMogoSearchManager = mMogoServiceApis.getSearchManagerApi();
+ mIMogoMarkerService = mMogoServiceApis.getMarkerService();
+
+ mMarkerManager = mMapService.getMarkerManager(context);
+ mNavi = mMapService.getNavi(context);
+ mMapUIController = mMapService.getMapUIController();
+ mMogoLocationClient = mMapService.getSingletonLocationClient(context);
+ mMogoOverlayManager = mMapService.getOverlayManager(context);
+ mIMogoGeoSearch = mMapService.getGeoSearch(context);
+
+ mCarsChattingProvider = (ICarsChattingProvider) ARouter.getInstance().build(CallChattingProviderConstant.CAR_CALL_PROVIDER).navigation();
+ mMogoIntentManager = mMogoServiceApis.getIntentManagerApi();
+
+ mV2XRefreshModel = V2XRefreshModel.getInstance(context);
+ mV2XMarkerService = V2XMarkerService.getInstance(context);
+ mV2XStatusManager = V2XStatusManager.getInstance();
+ mV2XSocketManager = V2XSocketManager.getInstance();
+ mV2XCalculateServer = V2XCalculateServer.getInstance();
+
+ moGoV2XMarkerManager = (IMoGoV2XMarkerManager) ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_MARKER_MANAGER).navigation(context);
+ moGoV2XPolylineManager = (IMoGoV2XPolylineManager) ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_POLYLINE_MANAGER).navigation(context);
+ moGoV2XStatusManager = (IMoGoV2XStatusManager) ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_STATUS_MANAGER).navigation(context);
+ }
+
+ public static Context getContext() {
+ return mContext;
+ }
+
+ public static IMogoTopViewManager getMogoTopViewManager() {
+ return mMogoTopViewManager;
+ }
+
+ public static IMogoEntranceButtonController getMogoEntranceButtonController() {
+ return mMogoEntranceButtonController;
+ }
+
+ public static IMogoMapService getMapService() {
+ return mMapService;
+ }
+
+ public static IMogoOverlayManager getMogoOverlayManager() {
+ return mMogoOverlayManager;
+ }
+
+ public static IMogoRegisterCenter getMogoRegisterCenter() {
+ return mMogoRegisterCenter;
+ }
+
+ public static IMogoMarkerManager getMarkerManager() {
+ return mMarkerManager;
+ }
+
+ public static IMogoNavi getNavi() {
+ return mNavi;
+ }
+
+ public static IMogoMapUIController getMapUIController() {
+ return mMapUIController;
+ }
+
+ public static IMogoLocationClient getMogoLocationClient() {
+ return mMogoLocationClient;
+ }
+
+ public static IMogoImageloader getImageLoader() {
+ return mImageLoader;
+ }
+
+ public static IMogoSocketManager getMoGoSocketManager() {
+ return mMogoSocketManager;
+ }
+
+ public static IMogoStatusManager getMoGoStatusManager() {
+ return mMogoStatusManager;
+ }
+
+ public static IMogoWindowManager getIMogoWindowManager() {
+ return mIMogoWindowManager;
+ }
+
+ public static ICarsChattingProvider getCarsChattingProvider() {
+ return mCarsChattingProvider;
+ }
+
+ public static IMogoIntentManager getMogoIntentManager() {
+ return mMogoIntentManager;
+ }
+
+ public static V2XMarkerService getV2XMarkerService() {
+ return mV2XMarkerService;
+ }
+
+ public static V2XRefreshModel getV2XRefreshModel() {
+ return mV2XRefreshModel;
+ }
+
+ public static V2XStatusManager getV2XStatusManager() {
+ return mV2XStatusManager;
+ }
+
+ public static V2XSocketManager getV2XSocketManager() {
+ return mV2XSocketManager;
+ }
+
+ public static IMoGoV2XMarkerManager getMoGoV2XMarkerManager() {
+ return moGoV2XMarkerManager;
+ }
+
+ public static IMoGoV2XPolylineManager getMoGoV2XPolylineManager() {
+ return moGoV2XPolylineManager;
+ }
+
+ public static IMoGoV2XStatusManager getMoGoV2XStatusManager() {
+ return moGoV2XStatusManager;
+ }
+
+ public static IMogoActionManager getMogoActionManager() {
+ return mMogoActionManager;
+ }
+
+ public static IMogoGeoSearch getMogoGeoSearch() {
+ return mIMogoGeoSearch;
+ }
+
+ public static IMogoSearchManager getSearchManager() {
+ return mIMogoSearchManager;
+ }
+
+ public static IMogoRefreshStrategyController getIMogoRefreshStrategyController() {
+ return mIMogoRefreshStrategyController;
+ }
+
+ public static IMogoAnalytics getMogoAnalytics() {
+ return mMogoAnalytics;
+ }
+
+ public static IMogoMarkerService getIMogoMarkerService() {
+ return mIMogoMarkerService;
+ }
+
+ public static V2XCalculateServer getV2XCalculateServer() {
+ return mV2XCalculateServer;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XSocketManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XSocketManager.java
new file mode 100644
index 0000000000..c6163caa39
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XSocketManager.java
@@ -0,0 +1,209 @@
+package com.mogo.module.v2x;
+
+import com.mogo.module.v2x.listener.V2XMessageListener_401003;
+import com.mogo.module.v2x.listener.V2XMessageListener_401005;
+import com.mogo.module.v2x.listener.V2XMessageListener_401006;
+import com.mogo.module.v2x.listener.V2XMessageListener_401007;
+import com.mogo.module.v2x.listener.V2XMessageListener_401009;
+import com.mogo.module.v2x.listener.V2XMessageListener_401010;
+import com.mogo.module.v2x.listener.V2XMessageListener_401011;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/31 5:59 PM
+ * desc : V2X报警事件管理,这里进行报警事件的分发处理,TODO 这里是准备重构使用的
+ * version: 1.0
+ */
+public class V2XSocketManager {
+
+ private static V2XSocketManager mV2XSocketManager;
+
+ private V2XMessageListener_401011 v2XMessageListener_401001;
+ private V2XMessageListener_401003 v2XMessageListener_401003;
+ private V2XMessageListener_401005 v2XMessageListener_401005;
+ private V2XMessageListener_401006 v2XMessageListener_401006;
+ private V2XMessageListener_401007 v2XMessageListener_401007;
+ private V2XMessageListener_401009 v2XMessageListener_401009;
+ private V2XMessageListener_401010 v2XMessageListener_401010;
+
+
+ private V2XSocketManager() {
+ }
+
+ /**
+ * 获取操作实体
+ */
+ public static synchronized V2XSocketManager getInstance() {
+ synchronized (V2XSocketManager.class) {
+ if (mV2XSocketManager == null) {
+ mV2XSocketManager = new V2XSocketManager();
+ }
+ }
+ return mV2XSocketManager;
+ }
+
+ /**
+ * 注册长链接消息处理
+ */
+ public void registerSocketMessage() {
+ Logger.d(MODULE_NAME, "开始注册Socket通道....");
+ register401011();
+ register401005();
+ register401007();
+ register401009();
+ // TODO 这里是前瞻需求,量产版本需要注释
+ //register401003();
+ // TODO 旧版本的一种V2X预警形式,已经废弃了
+ //register401006();
+ }
+
+ /**
+ * 反注册消息通道,不再进行接受
+ */
+ public void unregisterSocketMessage() {
+ Logger.w(MODULE_NAME, "反注册Socket通道....");
+ if (v2XMessageListener_401001 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401011, v2XMessageListener_401001);
+ }
+ if (v2XMessageListener_401003 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401003, v2XMessageListener_401003);
+ }
+ if (v2XMessageListener_401005 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401005, v2XMessageListener_401005);
+ }
+ if (v2XMessageListener_401006 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401006, v2XMessageListener_401006);
+ }
+ if (v2XMessageListener_401007 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401007, v2XMessageListener_401007);
+ }
+ if (v2XMessageListener_401009 != null) {
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .unregisterOnMessageListener(401009, v2XMessageListener_401009);
+ }
+ }
+
+ /**
+ * 道路事件,在线车辆绘制
+ */
+ private void register401011() {
+ v2XMessageListener_401001 = new V2XMessageListener_401011();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401011,
+ v2XMessageListener_401001
+ );
+ }
+
+ /**
+ * ADAS & V2X 场景触发push
+ * TODO 这里是后台下发 http://h5service.zhidaohulian.com/v2x_remoteControl/#/
+ */
+ private void register401003() {
+ v2XMessageListener_401003 = new V2XMessageListener_401003();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401003,
+ v2XMessageListener_401003
+ );
+ }
+
+ /**
+ * 特殊车辆推送绘制
+ */
+ private void register401005() {
+ v2XMessageListener_401005 = new V2XMessageListener_401005();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401005,
+ v2XMessageListener_401005
+ );
+ }
+
+ /**
+ * * 3.2.1、前方静止or慢速车辆报警
+ * * 3.2.2、道路危险状况告警 / 前方拥堵告警
+ */
+ @Deprecated
+ private void register401006() {
+ v2XMessageListener_401006 = new V2XMessageListener_401006();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401006,
+ v2XMessageListener_401006
+ );
+ }
+
+ /**
+ * 限行通知
+ */
+ private void register401007() {
+ v2XMessageListener_401007 = new V2XMessageListener_401007();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401007,
+ v2XMessageListener_401007
+ );
+ }
+
+ /**
+ * * 2.0.2
+ * * http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=35786774
+ * * 注册点赞通信接收
+ */
+ public void register401009() {
+ v2XMessageListener_401009 = new V2XMessageListener_401009();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401009,
+ v2XMessageListener_401009
+ );
+ }
+
+
+ /**
+ * * 2.0.3
+ * * http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=35788659
+ * * TODO 停车场、加油站推送心跳,这里是前瞻的功能,目前仅在分体机使用,
+ */
+ @Deprecated
+ private void register401010() {
+ v2XMessageListener_401010 = new V2XMessageListener_401010();
+ // 道路事件,在线车辆绘制
+ V2XServiceManager
+ .getMoGoSocketManager()
+ .registerOnMessageListener(
+ 401010,
+ v2XMessageListener_401010
+ );
+ }
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XStatusManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XStatusManager.java
new file mode 100644
index 0000000000..12396a786e
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XStatusManager.java
@@ -0,0 +1,62 @@
+package com.mogo.module.v2x;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/3 2:34 PM
+ * desc : V2X状态管理
+ * version: 1.0
+ */
+@Deprecated
+public class V2XStatusManager {
+ private static V2XStatusManager mV2XStatusManager;
+ // 正在进行的告警事件详情
+ private V2XRoadEventEntity mAlarmInfo;
+
+ private MogoLocation mLocation;
+
+ private V2XStatusManager() {
+ }
+
+ /**
+ * 获取操作实体
+ */
+ public static synchronized V2XStatusManager getInstance() {
+ synchronized (V2XStatusManager.class) {
+ if (mV2XStatusManager == null) {
+ mV2XStatusManager = new V2XStatusManager();
+ }
+ }
+ return mV2XStatusManager;
+ }
+
+ public void setAlarmInfo(V2XRoadEventEntity eventEntity) {
+ this.mAlarmInfo = eventEntity;
+ }
+
+ // 获取目标事件经纬度
+ public MogoLatLng getTargetMoGoLatLng() {
+ if (mAlarmInfo != null) {
+ return new MogoLatLng(
+ mAlarmInfo.getLocation().getLat(),
+ mAlarmInfo.getLocation().getLon()
+ );
+ }
+ return null;
+ }
+
+ public MogoLocation getLocation() {
+ if (mLocation == null) {
+ mLocation = new MogoLocation();
+ }
+ return mLocation;
+ }
+
+ public void setLocation(MogoLocation mLocation) {
+ this.mLocation = mLocation;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XPushEventAdapter.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XPushEventAdapter.java
new file mode 100644
index 0000000000..3dae739ced
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XPushEventAdapter.java
@@ -0,0 +1,49 @@
+package com.mogo.module.v2x.adapter;
+
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.v2x.adapter.holder.V2XPushEventDetailVH;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:05 PM
+ * desc : V2X 场景事件列表中的数据适配器
+ * version: 1.0
+ */
+public class V2XPushEventAdapter extends RecyclerView.Adapter {
+
+ private List itemList;
+
+ public V2XPushEventAdapter(List itemList) {
+ this.itemList = itemList;
+ }
+
+ @NonNull
+ @Override
+ public V2XPushEventDetailVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new V2XPushEventDetailVH(parent);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull V2XPushEventDetailVH holder, int position) {
+ holder.initView(itemList.get(position));
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return itemList.get(position).getViewType();
+ }
+
+ @Override
+ public int getItemCount() {
+ return itemList == null ? 0 : itemList.size();
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XRoadEventAdapter.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XRoadEventAdapter.java
new file mode 100644
index 0000000000..5988112df7
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XRoadEventAdapter.java
@@ -0,0 +1,67 @@
+package com.mogo.module.v2x.adapter;
+
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.v2x.adapter.holder.V2XLiveVideoVH;
+import com.mogo.module.v2x.adapter.holder.V2XRoadEventDetailVH;
+import com.mogo.module.common.entity.V2XWindowTypeEnum;
+
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:05 PM
+ * desc : V2X 场景事件列表中的数据适配器
+ * version: 1.0
+ */
+public class V2XRoadEventAdapter extends RecyclerView.Adapter {
+
+ private List itemList;
+
+ public V2XRoadEventAdapter(List itemList) {
+ this.itemList = itemList;
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ RecyclerView.ViewHolder holder;
+ switch (viewType) {
+ case V2XWindowTypeEnum.LIVE_CAR_WINDOW:
+ holder = new V2XLiveVideoVH(parent);
+ break;
+ case V2XWindowTypeEnum.ROAD_EVENT_WINDOW:
+ holder = new V2XRoadEventDetailVH(parent);
+ break;
+ default:
+ holder = new V2XRoadEventDetailVH(parent);
+ }
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ if (holder instanceof V2XLiveVideoVH) {
+ ((V2XLiveVideoVH) holder).initView(itemList.get(position));
+ }
+ if (holder instanceof V2XRoadEventDetailVH) {
+ ((V2XRoadEventDetailVH) holder).initView(itemList.get(position));
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return itemList.get(position).getViewType();
+ }
+
+ @Override
+ public int getItemCount() {
+ return itemList == null ? 0 : itemList.size();
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XSeekHelpAdapter.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XSeekHelpAdapter.java
new file mode 100644
index 0000000000..09f0e3441b
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/V2XSeekHelpAdapter.java
@@ -0,0 +1,217 @@
+package com.mogo.module.v2x.adapter;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.carchattingprovider.ICarsChattingProvider;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.imageloader.MogoImageView;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.carchattingprovider.ICallChatResponse;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+/**
+ * author : fenghualong
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:05 PM
+ * desc : V2X 其他车辆发起的故障求助
+ * version: 1.0
+ */
+public class V2XSeekHelpAdapter extends RecyclerView.Adapter {
+ private static final String TAG = V2XSeekHelpAdapter.class.getSimpleName();
+ private List itemList;
+ private LayoutInflater mInflater;
+
+ public V2XSeekHelpAdapter(Context context) {
+ itemList = new ArrayList<>();
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public void addDataList(List list) {
+ if (itemList == null) {
+ itemList = new ArrayList<>();
+ }
+ itemList.addAll(list);
+ }
+
+ public void addData(V2XMarkerEntity entity) {
+ if (itemList == null) {
+ itemList = new ArrayList<>();
+ }
+ itemList.add(entity);
+ }
+
+ public void removeData(V2XMarkerEntity entity) {
+ if (itemList != null) {
+ itemList.remove(entity);
+ }
+ }
+
+ public void removeData(int position) {
+ if (isPositionValid(position)) {
+ itemList.remove(position);
+ }
+ }
+
+ public void clearData() {
+ if (itemList != null) {
+ itemList.clear();
+ }
+ }
+
+ public boolean isPositionValid(int position) {
+ return position > -1 && itemList != null && itemList.size() > position;
+ }
+
+ @NonNull
+ @Override
+ public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = mInflater.inflate(R.layout.item_v2x_fault_help, parent, false);
+ return new MyViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
+ if (isPositionValid(position)) {
+ V2XMarkerEntity entity = itemList.get(position);
+ if (entity != null) {
+ V2XMarkerEntity.UserInfoBean infoBean = entity.getUserInfo();
+ if (infoBean != null) {
+ long time = entity.getCreateTime();
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.CHINA);
+ String eventDistance = String.format("距离%d m", entity.getDistance());
+ String eventTime = String.format("%s发布求助信息", sdf.format(new Date(time)));
+ holder.initView(infoBean.getHeadImgUrl(), infoBean.getDisplayName(), eventDistance, eventTime);
+ }
+ }
+ Log.d(TAG, "onBindViewHolder position=$position, entity= " + entity);
+ setCallData(holder.ivCall, entity);
+ //setCallDataWait(holder.ivCall, entity);
+ holder.ivNavi.setOnClickListener(v -> {
+ if (mListener != null && !V2XUtils.isFastClick()) {
+
+ mListener.onViewNaviClick(entity.getLat(), entity.getLon());
+ }
+ });
+ }
+ }
+
+ private void setCallData(ImageView ivCall, V2XMarkerEntity entity) {
+ ICarsChattingProvider provider = V2XServiceManager.getCarsChattingProvider();
+ // 判断是否可以打电话
+ ChartingUtil.isCanCall(b -> {
+ if (b) {
+ // 判断是否可以打电话
+ ChartingUtil.isOnLine(entity.getSn(), b1 -> {
+ if (b1) {
+ ivCall.setVisibility(VISIBLE);
+ } else {
+ ivCall.setVisibility(GONE);
+ }
+ });
+ } else {
+ ivCall.setVisibility(GONE);
+ }
+ });
+ ivCall.setOnClickListener(v -> {
+ if (!V2XUtils.isFastClick()) {
+ provider.isOnLine(V2XConst.MODULE_NAME, ivCall.getContext(), entity.getSn(), new ICallChatResponse() {
+ @Override
+ public void isOnLine(boolean isOnline, @Nullable String s) {
+ provider.canCall(V2XConst.MODULE_NAME, ivCall.getContext(), new ICallChatResponse() {
+ @Override
+ public void canCall(boolean canCall) {
+ Logger.d(TAG, "调用车聊聊,查询状态! SN=" + entity.getSn() + " is online: " + isOnline + " canCall: " + canCall + ", thread: " + Thread.currentThread().getName());
+ V2XUtils.runOnUiThread(() -> {
+ if (mListener != null && isOnline && canCall) {
+ mListener.onViewChatClick(entity);
+ }
+ });
+
+ }
+ });
+ }
+ }
+ );
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return itemList != null ? itemList.size() : 0;
+ }
+
+ static class MyViewHolder extends RecyclerView.ViewHolder {
+ MogoImageView ivHead;
+ TextView tvName;
+ TextView tvDistance;
+ TextView tvEventTime;
+ ImageView ivCall;
+ ImageView ivNavi;
+
+ MyViewHolder(@NonNull View itemView) {
+ super(itemView);
+ ivHead = itemView.findViewById(R.id.ivFaultHelpHead);
+ tvName = itemView.findViewById(R.id.tvFaultHelpName);
+ tvDistance = itemView.findViewById(R.id.tvFaultHelpDistance);
+ tvEventTime = itemView.findViewById(R.id.tvFaultHelpEventTime);
+ ivCall = itemView.findViewById(R.id.ivFaultHelpEventCall);
+ ivNavi = itemView.findViewById(R.id.ivFaultHelpEventNavi);
+ }
+
+ void initView(String headUrl, String name, String distance, String eventTime) {
+ if (!TextUtils.isEmpty(headUrl)) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(headUrl, ivHead);
+ }
+ tvName.setText(name);
+ tvDistance.setText(distance);
+ tvEventTime.setText(eventTime);
+ }
+ }
+
+ private OnViewClickListener mListener;
+
+ public void setOnViewClickListener(OnViewClickListener listener) {
+ mListener = listener;
+ }
+
+ public interface OnViewClickListener {
+ /**
+ * 点击事件,打电话给车聊聊
+ *
+ * @param entity
+ */
+ void onViewChatClick(V2XMarkerEntity entity);
+
+ /**
+ * 点击事件,导航去故障车位置
+ */
+ void onViewNaviClick(double lat, double lng);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XLiveVideoVH.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XLiveVideoVH.java
new file mode 100644
index 0000000000..043fe6b31f
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XLiveVideoVH.java
@@ -0,0 +1,244 @@
+package com.mogo.module.v2x.adapter.holder;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.view.Gravity;
+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.commons.debug.DebugConfig;
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.common.entity.MarkerCarInfo;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerUserInfo;
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.common.entity.V2XLiveCarInfoEntity;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XUserInfoRes;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventScenario;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.module.v2x.utils.TrackUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.view.V2XLiveGSYVideoView;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.imageloader.MogoImageView;
+import com.mogo.utils.logger.Logger;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:35 PM
+ * desc : 直播类型的卡片
+ * version: 1.0
+ */
+public class V2XLiveVideoVH extends RecyclerView.ViewHolder {
+
+ private V2XLiveGSYVideoView videoPlayer;
+ private MogoImageView ivReportHead;
+
+ // 控制按钮
+ private ImageView ivRoadCallChart;
+ private ImageView ivRoadEventLike;
+
+ // 上传事件的用户信息
+ private MarkerUserInfo mUserInfo = new MarkerUserInfo();
+ // 直播车机数据
+ private V2XLiveCarInfoEntity mV2XLiveCarEntity;
+ // 预警的道路事件数据
+ private V2XRoadEventEntity mV2XRoadEventEntity;
+
+ // 拨打车聊聊语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackCallListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ if (mUserInfo != null && !TextUtils.isEmpty(mUserInfo.getSn())) {
+ roadCallChart();
+ }
+ }
+ };
+ // 点赞语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackLickListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ if (mV2XLiveCarEntity != null) {
+ handlerZan(mV2XLiveCarEntity.getSn());
+ }
+ }
+ };
+
+ public V2XLiveVideoVH(ViewGroup viewGroup) {
+ super(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_v2x_live_video, viewGroup, false));
+ videoPlayer = itemView.findViewById(R.id.videoPlayer);
+ ivReportHead = itemView.findViewById(R.id.ivReportHead);
+
+ ivRoadCallChart = itemView.findViewById(R.id.ivRoadCallChart);
+ ivRoadEventLike = itemView.findViewById(R.id.ivRoadEventLike);
+
+ // 设置视图状态监听
+ itemView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ //Logger.w(MODULE_NAME, "列表View V2XLiveVideoVH 触发 onViewAttachedToWindow");
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING,
+ v2XVoiceCallbackCallListener)
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN,
+ v2XVoiceCallbackLickListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP,
+ v2XVoiceCallbackCallListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP,
+ v2XVoiceCallbackLickListener);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ //Logger.w(MODULE_NAME, "列表View V2XLiveVideoVH 触发 onViewDetachedFromWindow");
+ }
+ });
+ }
+
+ public void initView(V2XEventShowEntity v2XLiveCarEntity) {
+ mV2XRoadEventEntity = v2XLiveCarEntity.getV2XRoadEventEntity();
+ mV2XLiveCarEntity = v2XLiveCarEntity.getV2XLiveCarInfoRes();
+ initView(mV2XLiveCarEntity);
+ }
+
+ public void initView(V2XLiveCarInfoEntity v2XLiveCarEntity) {
+ mV2XLiveCarEntity = v2XLiveCarEntity;
+ // 由于车机自身推流的原因,这里为了浪费用户不必要的流量,用户滑动到了那个view展示了再进行直播信息的获取及展示
+ MarkerCarInfo.CarLiveInfo carLiveInfo = new MarkerCarInfo.CarLiveInfo();
+ carLiveInfo.setVideoSn(v2XLiveCarEntity.getSn());
+ videoPlayer.setCarLiveInfo(carLiveInfo);
+
+ ivRoadEventLike.setVisibility(VISIBLE);
+
+ ivRoadCallChart.setOnClickListener(v -> {
+ ivRoadCallChart.setVisibility(GONE);
+ roadCallChart();
+ });
+ ivRoadEventLike.setOnClickListener(v -> {
+ handlerZan(v2XLiveCarEntity.getSn());
+ });
+
+ requestUserInfo(v2XLiveCarEntity);
+ }
+
+ private void roadCallChart() {
+ MarkerLocation location = new MarkerLocation();
+ ChartingUtil.callChatting(mUserInfo, location);
+ }
+
+ /**
+ * 请求用户信息
+ *
+ * @param v2XLiveCarEntity 直播信息
+ */
+ private void requestUserInfo(V2XLiveCarInfoEntity v2XLiveCarEntity) {
+ Logger.d(MODULE_NAME, "上报事件的用户SN:" + v2XLiveCarEntity.getSn());
+ TrackUtils.trackV2xRoadEvent(mV2XRoadEventEntity.getNoveltyInfo().getInfoId(), v2XLiveCarEntity.getSn(), V2XConst.V2X_ROAD_VIDEO);
+ // 获取道路事件周边的直播车机
+ if (!TextUtils.isEmpty(v2XLiveCarEntity.getSn())) {
+ V2XServiceManager
+ .getV2XRefreshModel()
+ .queryUserInfoBySn(
+ v2XLiveCarEntity.getSn(),
+ new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(V2XUserInfoRes result) {
+ //Logger.d(MODULE_NAME, "上报事件的用户:" + result);
+ if (result != null &&
+ result.getResult() != null &&
+ result.getResult().getInfo() != null) {
+ V2XUserInfoRes.Result.Info infoBean = result.getResult().getInfo();
+ if (mUserInfo == null) {
+ mUserInfo = new MarkerUserInfo();
+ }
+ mUserInfo.setSn(infoBean.getSn());
+ try {
+ if (!TextUtils.isEmpty(infoBean.getCardIdAge())) {
+ mUserInfo.setAge(Integer.parseInt(infoBean.getCardIdAge()));
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ mUserInfo.setUserName(infoBean.getUserNickName());
+ mUserInfo.setUserHead(infoBean.getHeadImgUrl());
+ mUserInfo.setGender(infoBean.getCardIdSex());
+
+ if (DebugConfig.getCarMachineType() == DebugConfig.CAR_MACHINE_TYPE_SELF_INNOVATE) {
+ // 判断是否可以打电话
+ ChartingUtil.isCanCall(b -> {
+ if (b) {
+ // 判断是否可以打电话
+ ChartingUtil.isOnLine(mUserInfo.getSn(), b1 -> {
+ if (b1) {
+ ivRoadCallChart.setVisibility(VISIBLE);
+ } else {
+ ivRoadCallChart.setVisibility(GONE);
+ }
+ });
+ } else {
+ ivRoadCallChart.setVisibility(GONE);
+ }
+ });
+
+ }
+ if (!TextUtils.isEmpty(mUserInfo.getUserHead())) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(mUserInfo.getUserHead(), ivReportHead);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+ ivRoadCallChart.setVisibility(GONE);
+ }
+ });
+ }
+ }
+
+ private void handlerZan(String sn) {
+ try {
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("已点赞", null);
+ showTip("已点赞");
+ V2XServiceManager.getV2XMarkerService()
+ .getV2XRefreshModel()
+ .giveLikeLiveVideo(null, sn);
+ ivReportHead.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ V2XRoadEventScenario.getInstance().close();
+ }
+ }, 2000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void showTip(String msg) {
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ View toastView = LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view, null);
+ TextView msgView = toastView.findViewById(R.id.tvFeedbackContent);
+ msgView.setText(msg);
+ ToastUtils.showCustomShort(toastView);
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XPushEventDetailVH.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XPushEventDetailVH.java
new file mode 100644
index 0000000000..a4f8226297
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XPushEventDetailVH.java
@@ -0,0 +1,297 @@
+package com.mogo.module.v2x.adapter.holder;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.view.Gravity;
+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.commons.voice.AIAssist;
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.navi.IMogoNaviListener;
+import com.mogo.map.navi.MogoNaviInfo;
+import com.mogo.map.navi.MogoTraffic;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerUserInfo;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.scenario.scene.push.V2XPushEventScenario;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.imageloader.MogoImageView;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:35 PM
+ * desc : TODO 这里是前瞻演示需求,推送的消息,
+ * version: 1.0
+ */
+public class V2XPushEventDetailVH extends RecyclerView.ViewHolder implements IMogoNaviListener {
+ private MogoImageView ivImg;
+ private MogoImageView ivReportHead;
+
+ // 控制按钮
+ private ImageView ivRoadReportTrue;
+ private ImageView ivRoadReportErr;
+ private ImageView ivRoadCallChart;
+ private ImageView ivRoadEventNav;
+ private ImageView ivRoadEventLike;
+
+ // 上传事件的用户信息
+ private MarkerUserInfo mUserInfo = new MarkerUserInfo();
+
+ private V2XPushMessageEntity mV2XRoadEventEntity;
+
+ // 语音控制导航
+ private V2XVoiceCallbackListener mNaviCb = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ startNavi();
+ }
+ };
+ // 语音控制拨打电话
+ private V2XVoiceCallbackListener mCallChartingCb = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ roadCallChart();
+ }
+ };
+ // 点赞语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackLickListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ handlerZan();
+ }
+ };
+
+ public V2XPushEventDetailVH(ViewGroup viewGroup) {
+ super(LayoutInflater.from(viewGroup.getContext())
+ .inflate(R.layout.item_v2x_push_event_detail, viewGroup, false));
+ ivImg = itemView.findViewById(R.id.ivImg);
+ ivReportHead = itemView.findViewById(R.id.ivReportHead);
+
+ ivRoadReportTrue = itemView.findViewById(R.id.ivRoadReportTrue);
+ ivRoadReportErr = itemView.findViewById(R.id.ivRoadReportErr);
+ ivRoadCallChart = itemView.findViewById(R.id.ivRoadCallChart);
+ ivRoadEventNav = itemView.findViewById(R.id.ivRoadEventNav);
+ ivRoadEventLike = itemView.findViewById(R.id.ivRoadEventLike);
+
+ ivRoadEventNav.getParent().getParent().requestDisallowInterceptTouchEvent(true);
+ ivRoadEventNav.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startNavi();
+ }
+ });
+ ivRoadCallChart.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ roadCallChart();
+ }
+ });
+ ivRoadEventLike.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ handlerZan();
+ }
+ });
+
+ // 设置视图状态监听
+ itemView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ //Logger.w(MODULE_NAME, "列表View V2XPushEventDetailVH 触发 onViewAttachedToWindow");
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI,
+ mNaviCb)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP,
+ mNaviCb)
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING,
+ mCallChartingCb)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP,
+ mCallChartingCb)
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN,
+ v2XVoiceCallbackLickListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP,
+ v2XVoiceCallbackLickListener);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ //Logger.w(MODULE_NAME, "列表View V2XPushEventDetailVH 触发 onViewDetachedFromWindow");
+ V2XServiceManager.getMogoRegisterCenter().unregisterMogoNaviListener(MODULE_NAME);
+ // 反注册语音交互
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REPORT)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_TRUE)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_ERROR)
+ .unRegisterPagingCallback();
+ }
+ });
+ }
+
+ public void initView(V2XPushMessageEntity v2XRoadEventEntity) {
+ mV2XRoadEventEntity = v2XRoadEventEntity;
+ if (!TextUtils.isEmpty(v2XRoadEventEntity.getMsgImgUrl())) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(v2XRoadEventEntity.getMsgImgUrl(), ivImg);
+ }
+ if (!TextUtils.isEmpty(v2XRoadEventEntity.getHeadImgUrl())) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(v2XRoadEventEntity.getHeadImgUrl(), ivReportHead);
+ }
+
+ switch (v2XRoadEventEntity.getSceneId()) {
+ case "100015"://取快递
+ case "100016"://顺风车
+ ivRoadEventNav.setVisibility(View.VISIBLE);
+ ivRoadCallChart.setVisibility(View.VISIBLE);
+ ivRoadReportTrue.setVisibility(View.GONE);
+ ivRoadReportErr.setVisibility(View.GONE);
+ ivRoadEventLike.setVisibility(View.GONE);
+
+ break;
+
+ case "100017"://政府公告
+ ivRoadEventLike.setVisibility(View.VISIBLE);
+ ivRoadCallChart.setVisibility(View.GONE);
+ ivRoadEventNav.setVisibility(View.GONE);
+ ivRoadReportTrue.setVisibility(View.GONE);
+ ivRoadReportErr.setVisibility(View.GONE);
+
+ break;
+ }
+
+ }
+
+ /**
+ * 打电话
+ */
+ private void roadCallChart() {
+ Logger.w(MODULE_NAME, "正在拨打电话。。。。");
+ if (mV2XRoadEventEntity != null) {
+ MarkerLocation location = new MarkerLocation();
+ location.setLon(mV2XRoadEventEntity.getLon());
+ location.setLat(mV2XRoadEventEntity.getLat());
+ mUserInfo.setSn(mV2XRoadEventEntity.getSn());
+ mUserInfo.setUserHead(mV2XRoadEventEntity.getHeadImgUrl());
+ mUserInfo.setUserName("蘑菇用户");
+ mUserInfo.setGender("男");
+ mUserInfo.setAge(30);
+ ChartingUtil.callChatting(mUserInfo, location);
+ delayedCloseWindow();
+ }
+ }
+
+ /**
+ * 点赞
+ */
+ private void handlerZan() {
+ try {
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("已点赞", null);
+ showTip("已点赞");
+ if (mV2XRoadEventEntity != null) {
+ V2XServiceManager.getV2XMarkerService()
+ .getV2XRefreshModel()
+ .giveLikeLiveVideo(null, mV2XRoadEventEntity.getSn());
+ }
+ delayedCloseWindow();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 延迟关闭窗体
+ */
+ private void delayedCloseWindow() {
+ itemView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ V2XPushEventScenario.getInstance().close();
+ }
+ }, 1000);
+ }
+
+ /**
+ * 导航规划路线
+ */
+ private void startNavi() {
+ if (mV2XRoadEventEntity != null) {
+ MogoLatLng endPoint = new MogoLatLng(mV2XRoadEventEntity.getLat(), mV2XRoadEventEntity.getLon());
+ V2XServiceManager.getNavi().naviTo(endPoint);
+ V2XServiceManager.getMogoRegisterCenter().unregisterMogoNaviListener(MODULE_NAME);
+ V2XServiceManager.getMogoRegisterCenter().registerMogoNaviListener(MODULE_NAME, this);
+ delayedCloseWindow();
+ }
+ }
+
+ private void showTip(String msg) {
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ View toastView = LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view, null);
+ TextView msgView = toastView.findViewById(R.id.tvFeedbackContent);
+ msgView.setText(msg);
+ ToastUtils.showCustomShort(toastView);
+ }
+
+ @Override
+ public void onCalculateSuccess() {
+ V2XServiceManager.getNavi().startNavi(true);
+ }
+
+ @Override
+ public void onInitNaviFailure() {
+
+ }
+
+ @Override
+ public void onInitNaviSuccess() {
+
+ }
+
+ @Override
+ public void onNaviInfoUpdate(MogoNaviInfo naviinfo) {
+
+ }
+
+ @Override
+ public void onStartNavi() {
+
+ }
+
+ @Override
+ public void onStopNavi() {
+
+ }
+
+ @Override
+ public void onoCalculateFailed() {
+
+ }
+
+ @Override
+ public void onUpdateTraffic(MogoTraffic traffic) {
+
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XRoadEventDetailVH.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XRoadEventDetailVH.java
new file mode 100644
index 0000000000..67841a9ea1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/adapter/holder/V2XRoadEventDetailVH.java
@@ -0,0 +1,435 @@
+package com.mogo.module.v2x.adapter.holder;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.view.Gravity;
+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.elegant.utils.ArrayUtils;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerUserInfo;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XUserInfoRes;
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.common.entity.V2XLiveCarInfoEntity;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.common.entity.V2XWindowTypeEnum;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.scenario.scene.livecar.V2XRoadLiveCarScenario;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventScenario;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventWindow;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.module.v2x.utils.EventTypeUtils;
+import com.mogo.module.v2x.utils.RoadConditionUtils;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.module.v2x.utils.TrackUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.imageloader.MogoImageView;
+import com.mogo.utils.DateTimeUtils;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:35 PM
+ * desc : 道路事件详情
+ * version: 1.0
+ */
+public class V2XRoadEventDetailVH extends RecyclerView.ViewHolder {
+ private MogoImageView ivEventImg;
+ private MogoImageView ivReportHead;
+ private ImageView ivEventPlay;
+
+ // 控制按钮
+ private TextView tvEventTypeTitle;
+ private TextView tvEventAddress;
+ private TextView tvEventDistance;
+ private TextView tvEventTime;
+ private ImageView ivEventLive;
+ private ImageView ivEventCallChart;
+ private ImageView ivEventReportTrue;
+ private ImageView ivEventReportErr;
+ private ImageView ivEventZan;
+
+
+ // 上传事件的用户信息
+ private MarkerUserInfo mUserInfo = new MarkerUserInfo();
+ // 当前的新鲜事儿信息
+ private MarkerExploreWay mNoveltyInfo;
+ private V2XRoadEventEntity mV2XRoadEventEntity;
+ private V2XEventShowEntity mV2XEventShowEntity;
+
+ // 拨打车聊聊语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackCallListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ roadCallChart(mNoveltyInfo);
+ }
+ };
+ // 点赞语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackLickListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ handlerZan(mNoveltyInfo);
+ }
+ };
+ // 反馈"正确"语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackReportTrueListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ roadReportTrue(mNoveltyInfo);
+ }
+ };
+ // 反馈"错误"语音回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackReportErrorListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ roadReportErr(mNoveltyInfo);
+ }
+ };
+ // 反馈"错误"语音回调
+ private V2XVoiceCallbackListener v2XVoiceOpenLiveListener = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ showLiveCar(mV2XEventShowEntity);
+ }
+ };
+
+ private void init(View itemView) {
+ ivEventImg = itemView.findViewById(R.id.ivEventImg);
+ ivReportHead = itemView.findViewById(R.id.ivEventHead);
+ ivEventPlay = itemView.findViewById(R.id.ivEventPlay);
+ tvEventTypeTitle = itemView.findViewById(R.id.tvEventTypeTitle);
+ tvEventAddress = itemView.findViewById(R.id.tvEventAddress);
+ tvEventDistance = itemView.findViewById(R.id.tvEventDistance);
+ tvEventTime = itemView.findViewById(R.id.tvEventTime);
+ ivEventLive = itemView.findViewById(R.id.ivEventLive);
+ ivEventCallChart = itemView.findViewById(R.id.ivEventCallChart);
+ ivEventZan = itemView.findViewById(R.id.ivEventZan);
+ ivEventReportTrue = itemView.findViewById(R.id.ivEventReportTrue);
+ ivEventReportErr = itemView.findViewById(R.id.ivEventReportErr);
+ }
+
+ public V2XRoadEventDetailVH(ViewGroup viewGroup) {
+ super(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_v2x_event_detail, viewGroup, false));
+ init(itemView);
+ // 设置视图状态监听
+ itemView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+// Logger.w(MODULE_NAME, "列表View V2XRoadEventDetailVH 触发 onViewAttachedToWindow");
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING,
+ v2XVoiceCallbackCallListener)
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN,
+ v2XVoiceCallbackLickListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP,
+ v2XVoiceCallbackCallListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP,
+ v2XVoiceCallbackLickListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_TRUE,
+ v2XVoiceCallbackReportTrueListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_ERROR,
+ v2XVoiceCallbackReportErrorListener);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+// Logger.w(MODULE_NAME, "列表View V2XRoadEventDetailVH 触发 onViewDetachedFromWindow");
+ }
+ });
+ }
+
+ public void initView(V2XEventShowEntity v2XEventShowEntity) {
+ try {
+ if (v2XEventShowEntity == null) {
+ return;
+ }
+ mV2XEventShowEntity = v2XEventShowEntity;
+ mV2XRoadEventEntity = v2XEventShowEntity.getV2XRoadEventEntity();
+ if (mV2XRoadEventEntity == null) {
+ return;
+ }
+ mNoveltyInfo = mV2XRoadEventEntity.getNoveltyInfo();
+ if (mNoveltyInfo != null) {
+ //Logger.d(MODULE_NAME, "mContentData:" + mContentData);
+ if (!ArrayUtils.isEmpty(mNoveltyInfo.getItems())) {
+ String imgUrl = mNoveltyInfo.getItems().get(0).getThumbnail();
+ if (TextUtils.isEmpty(imgUrl)) {
+ imgUrl = mNoveltyInfo.getItems().get(0).getUrl();
+ }
+ if (!TextUtils.isEmpty(imgUrl)) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(imgUrl, ivEventImg);
+ }
+ }
+ if (mNoveltyInfo.getUserInfo() != null &&
+ !TextUtils.isEmpty(mNoveltyInfo.getUserInfo().getUserHead())) {
+ V2XServiceManager.getImageLoader()
+ .displayImage(mNoveltyInfo.getUserInfo().getUserHead(), ivReportHead);
+ }
+
+ String poiType = EventTypeUtils.getPoiTypeStr(mNoveltyInfo.getPoiType());
+ if (!TextUtils.isEmpty(poiType)) {
+ tvEventTypeTitle.setText(poiType);
+ tvEventTypeTitle.setBackgroundResource(EventTypeUtils.getPoiTypeBg(mNoveltyInfo.getPoiType()));
+ }
+ tvEventAddress.setText(mNoveltyInfo.getAddr());
+ tvEventDistance.setText("距离 " + (int) mNoveltyInfo.getDistance() + "M");
+
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(mNoveltyInfo.getGenerateTime());
+ String eventTime = DateTimeUtils.printCalendarByPattern(c, "yyyy/MM/dd HH:mm");
+ if (!TextUtils.isEmpty(eventTime)) {
+ tvEventTime.setText(eventTime);
+ }
+
+ // 事件距离车辆小于50米的时候可以用户纠错
+ if (mV2XRoadEventEntity.getDistance() < 50) {
+ ivEventReportTrue.setVisibility(VISIBLE);
+ ivEventReportErr.setVisibility(VISIBLE);
+
+ ivEventLive.setVisibility(GONE);
+ ivEventZan.setVisibility(GONE);
+ } else {
+ if (!ArrayUtils.isEmpty(mV2XEventShowEntity.getV2XLiveCarList())) {
+ ivEventLive.setVisibility(VISIBLE);
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_LIVE_ROAD,
+ v2XVoiceOpenLiveListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_OPEN_LIVE_UN_WAKEUP,
+ v2XVoiceOpenLiveListener);
+ ivEventLive.setOnClickListener(v -> {
+ showLiveCar(v2XEventShowEntity);
+ });
+ } else {
+ ivEventLive.setVisibility(GONE);
+ }
+
+ ivEventReportTrue.setVisibility(GONE);
+ ivEventReportErr.setVisibility(GONE);
+ ivEventZan.setVisibility(VISIBLE);
+
+ // 用户上报的才会展示拨打电话
+ if (!TextUtils.isEmpty(mNoveltyInfo.getUploadType())
+ && mNoveltyInfo.getUploadType().equals("1")) {
+ requestUserInfo(mNoveltyInfo);
+ }
+ }
+
+ ivEventReportTrue.setOnClickListener(v -> {
+ roadReportTrue(mNoveltyInfo);
+ });
+ ivEventReportErr.setOnClickListener(v -> {
+ roadReportErr(mNoveltyInfo);
+ });
+ ivEventCallChart.setOnClickListener(v -> {
+ ivEventCallChart.setVisibility(GONE);
+ roadCallChart(mNoveltyInfo);
+ });
+ ivEventZan.setOnClickListener(v -> {
+ handlerZan(mNoveltyInfo);
+ });
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 展示直播信息
+ *
+ * @param v2XEventShowEntity
+ */
+ private void showLiveCar(V2XEventShowEntity v2XEventShowEntity) {
+ if (v2XEventShowEntity != null) {
+ // 展示周边的直播车辆
+ List eventShowEntityArrayList = new ArrayList<>();
+ for (V2XLiveCarInfoEntity v2XLiveCarInfoRes : v2XEventShowEntity.getV2XLiveCarList()) {
+ V2XEventShowEntity showEntity = new V2XEventShowEntity();
+ showEntity.setViewType(V2XWindowTypeEnum.LIVE_CAR_WINDOW);
+ showEntity.setV2XLiveCarInfoRes(v2XLiveCarInfoRes);
+ showEntity.setV2XRoadEventEntity(mV2XRoadEventEntity);
+ eventShowEntityArrayList.add(showEntity);
+ }
+
+ Logger.d(MODULE_NAME, "要展示的直播:" + GsonUtil.jsonFromObject(eventShowEntityArrayList));
+ V2XMessageEntity> v2XMessageEntity = new V2XMessageEntity<>();
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_LIVE_CAR_WARNING);
+ v2XMessageEntity.setContent(eventShowEntityArrayList);
+ v2XMessageEntity.setShowState(true);
+ V2XRoadLiveCarScenario.getInstance().init(v2XMessageEntity);
+
+ // 打开直播后,窗口倒计时暂停关闭,直播被关闭后继续倒计时
+ V2XRoadEventWindow window = (V2XRoadEventWindow) V2XRoadEventScenario.getInstance().getV2XWindow();
+ window.stopCountDown();
+ }
+ }
+
+ private void requestUserInfo(MarkerExploreWay noveltyInfo) {
+ Logger.d(MODULE_NAME, "上报事件的用户SN:" + noveltyInfo.getSn());
+ // 获取道路事件周边的直播车机
+ if (!TextUtils.isEmpty(noveltyInfo.getSn())) {
+ V2XServiceManager
+ .getV2XRefreshModel()
+ .queryUserInfoBySn(
+ noveltyInfo.getSn(),
+ new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(V2XUserInfoRes result) {
+ if (result != null && result.getResult() != null && result.getResult().getInfo() != null) {
+ V2XUserInfoRes.Result.Info infoBean = result.getResult().getInfo();
+ if (mUserInfo == null) {
+ mUserInfo = new MarkerUserInfo();
+ }
+ mUserInfo.setSn(infoBean.getSn());
+ try {
+ if (!TextUtils.isEmpty(infoBean.getCardIdAge())) {
+ mUserInfo.setAge(Integer.parseInt(infoBean.getCardIdAge()));
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ mUserInfo.setUserName(infoBean.getUserNickName());
+ mUserInfo.setUserHead(infoBean.getHeadImgUrl());
+ mUserInfo.setGender(infoBean.getCardIdSex());
+
+ if (DebugConfig.getCarMachineType() == DebugConfig.CAR_MACHINE_TYPE_SELF_INNOVATE) {
+ // 判断是否可以打电话
+ ChartingUtil.isCanCall(b -> {
+ if (b) {
+ // 判断是否可以打电话
+ ChartingUtil.isOnLine(mUserInfo.getSn(), b1 -> {
+ if (b1) {
+ ivEventCallChart.setVisibility(VISIBLE);
+ } else {
+ ivEventCallChart.setVisibility(GONE);
+ }
+ });
+ } else {
+ ivEventCallChart.setVisibility(GONE);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+ ivEventCallChart.setVisibility(GONE);
+ }
+ });
+ }
+ }
+
+
+ /**
+ * 打电话
+ */
+ private void roadCallChart(MarkerExploreWay noveltyInfo) {
+ MarkerLocation location = new MarkerLocation();
+ mUserInfo.setSn(noveltyInfo.getSn());
+ ChartingUtil.callChatting(mUserInfo, location);
+ TrackUtils.trackV2xRoadEvent(noveltyInfo.getInfoId(), noveltyInfo.getUserInfo().getSn(), V2XConst.V2X_ROAD_CHAT);
+ }
+
+ /**
+ * 反馈路况错误
+ */
+ private void roadReportErr(MarkerExploreWay noveltyInfo) {
+ if (noveltyInfo != null) {
+ RoadConditionUtils.sendDataErrorReceiverInfo(
+ noveltyInfo.getPoiType(),
+ noveltyInfo.getInfoId(),
+ "1");
+
+ TrackUtils.trackV2xRoadEvent(noveltyInfo.getInfoId(), noveltyInfo.getUserInfo().getSn(), V2XConst.V2X_ROAD_REPORT_ERROR);
+ }
+ delayedCloseWindow();
+ }
+
+ /**
+ * 反馈路况正确
+ */
+ private void roadReportTrue(MarkerExploreWay noveltyInfo) {
+ if (noveltyInfo != null) {
+ RoadConditionUtils.sendDataErrorReceiverInfo(
+ noveltyInfo.getPoiType(),
+ noveltyInfo.getInfoId(),
+ "2");
+ TrackUtils.trackV2xRoadEvent(noveltyInfo.getInfoId(), noveltyInfo.getUserInfo().getSn(), V2XConst.V2X_ROAD_REPORT_RIGHT);
+ }
+ delayedCloseWindow();
+ }
+
+ /**
+ * 点赞
+ */
+ private void handlerZan(MarkerExploreWay noveltyInfo) {
+ try {
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("已点赞", null);
+ showTip("已点赞");
+ if (noveltyInfo != null) {
+ V2XServiceManager.getV2XMarkerService()
+ .getV2XRefreshModel()
+ .giveLikeLiveVideo(null, noveltyInfo.getSn());
+ }
+ delayedCloseWindow();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ TrackUtils.trackV2xRoadEvent(noveltyInfo.getInfoId(), noveltyInfo.getUserInfo().getSn(), V2XConst.V2X_ROAD_ZAN);
+ }
+
+ /**
+ * 延迟关闭窗体
+ */
+ private void delayedCloseWindow() {
+ itemView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // 移除窗体
+ V2XServiceManager
+ .getIMogoWindowManager()
+ .removeView(V2XRoadEventScenario.getInstance().getV2XWindow().getView());
+ V2XRoadEventScenario.getInstance().close();
+ }
+ }, 1000);
+ }
+
+ private void showTip(String msg) {
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ View toastView = LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view, null);
+ TextView msgView = toastView.findViewById(R.id.tvFeedbackContent);
+ msgView.setText(msg);
+ ToastUtils.showCustomShort(toastView);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XAlarmServer.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XAlarmServer.java
new file mode 100644
index 0000000000..015f5e941c
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XAlarmServer.java
@@ -0,0 +1,408 @@
+package com.mogo.module.v2x.alarm;
+
+import android.text.TextUtils;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.map.search.geo.IMogoGeoSearchListener;
+import com.mogo.map.search.geo.MogoGeocodeResult;
+import com.mogo.map.search.geo.MogoPoiItem;
+import com.mogo.map.search.geo.MogoRegeocodeResult;
+import com.mogo.map.search.poisearch.IMogoPoiSearch;
+import com.mogo.map.search.poisearch.IMogoPoiSearchListener;
+import com.mogo.map.search.poisearch.MogoPoiResult;
+import com.mogo.map.search.poisearch.query.MogoPoiSearchQuery;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.service.Utils;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XStrategyPushRes;
+import com.mogo.module.v2x.utils.DrivingDirectionUtils;
+import com.mogo.module.v2x.utils.FatigueDrivingUtils;
+import com.mogo.module.v2x.utils.LocationUtils;
+import com.mogo.module.v2x.utils.TimeConstants;
+import com.mogo.module.v2x.utils.TimeUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.utils.ArrayUtils;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.storage.SharedPrefsMgr;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/13 11:02 AM
+ * desc :
+ * 这里是车机端自己实现预警信息的触发操作,首先获取当前车位置周围2公里范围的道路事件,
+ * 普通模式:根据当前「车辆位置」及「行驶方向」判断「车辆前方」「500米」是否有道路事件需要触发。
+ * 导航模式:根据当前「路径规划」及「行驶方向」判断「路径前方」「500米」是否有道路事件需要触发。
+ * version: 1.0
+ */
+public class V2XAlarmServer {
+ // 记录道路播报的事件
+ private static HashMap mAlertRoadEventList = new HashMap<>();
+ private static HashSet mAlertRoadEventCorrectionList = new HashSet<>();
+
+ // 记录违章停车播报事件
+ private static HashMap mAlertIllegalParkEventList = new HashMap<>();
+
+ // 记录疲劳驾驶播报的事件
+ private static HashSet mV2XFatigueDrivingEventLevel = new HashSet<>();
+
+ /**
+ * 获取当前车辆前方距离最近的道路事件
+ */
+ public static V2XRoadEventEntity getDriveFrontAlarmEvent(
+ CopyOnWriteArrayList v2XRoadEventEntityList,
+ MogoLocation currentLocation) {
+ try {
+// Logger.w(MODULE_NAME, "V2X预警--车辆状态:" + currentLocation);
+// Logger.w(MODULE_NAME, "V2X预警--车辆速度:" + currentLocation.getSpeed());
+// Logger.w(MODULE_NAME, "V2X预警--v2XRoadEventEntityList:" + GsonUtil.jsonFromObject(v2XRoadEventEntityList));
+ // 60(km/h)
+ if (currentLocation != null && v2XRoadEventEntityList != null) {
+ // 因为集合是按照距离排序后的所以这里检索出来第一个就发出警告
+ for (V2XRoadEventEntity v2XRoadEventEntity : v2XRoadEventEntityList) {
+ // 先计算当前车辆的车头朝向是否与事件方向相同,这里采用的是区间值,只要在20度上下即可使用
+ // 道路事件必须有朝向,角度>=0;
+ //Logger.w(MODULE_NAME,
+ // "V2X预警--车辆与事件信息:" +
+ // "\n事件名称:" + markerNoveltyInfo.getNoveltyInfo().getContentData().getTitle() +
+ // "\n事件角度:" + markerNoveltyInfo.getLocation().getAngle() +
+ // "\n车头角度:" + currentLocation.getAngle() +
+ // "\n角度差值:" + Math.abs(currentLocation.getAngle() - markerNoveltyInfo.getLocation().getAngle()));
+ if (v2XRoadEventEntity.getLocation().getAngle() >= 0 &&
+ Math.abs(currentLocation.getBearing() - v2XRoadEventEntity.getLocation().getAngle()) <= 10) {
+ // 计算车辆距离指定气泡的距离
+ MarkerLocation eventLocation = v2XRoadEventEntity.getLocation();
+
+ // 判断是否到达了触发距离,20 ~ 500,
+ if (v2XRoadEventEntity.getDistance() <= 500) {
+ double eventAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
+ currentLocation.getLongitude(),
+ currentLocation.getLatitude(),
+ eventLocation.getLon(),
+ eventLocation.getLat(),
+ (int) currentLocation.getBearing()
+ );
+ // Logger.w(MODULE_NAME, "V2X预警--事件位置===" + eventLocation);
+ if (0 <= eventAngle && eventAngle <= 20) {
+ // 判断是否已经提示过道路事件
+ boolean isAlreadyAlert = false;
+ String lastTime = mAlertRoadEventList.get(v2XRoadEventEntity);
+ if (!TextUtils.isEmpty(lastTime)) {
+ long timeSpan = TimeUtils.getTimeSpanByNow(lastTime, TimeConstants.MIN);
+// Logger.w(MODULE_NAME,
+// "V2X预警--事件ID:" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
+// "\n上一次预警时间:" + lastTime +
+// "\n距离当前时间:" + timeSpan);
+ // 5分钟内不重复提醒
+ if (timeSpan < 5) {
+ isAlreadyAlert = true;
+ }
+ }
+ // 判断是否是纠错,如果是纠错就忽略掉带有时间段的道路提醒
+ if (v2XRoadEventEntity.getDistance() <= 50) {
+ if (!mAlertRoadEventCorrectionList.contains(v2XRoadEventEntity)) {
+ mAlertRoadEventCorrectionList.add(v2XRoadEventEntity);
+ isAlreadyAlert = false;
+ }
+ }
+// Logger.w(MODULE_NAME, "V2X预警--车辆与事件信息:" +
+// "\n距离:" + v2XRoadEventEntity.getDistance() + "米" +
+// "\n是否已经提醒:" + isAlreadyAlert +
+// "\n事件ID:" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
+// "\n事件详情:" + GsonUtil.jsonFromObject(v2XRoadEventEntity.getNoveltyInfo())
+// );
+ // 进行提醒
+ if (!isAlreadyAlert) {
+ mAlertRoadEventList.put(v2XRoadEventEntity, TimeUtils.getNowString());
+ return v2XRoadEventEntity;
+ }
+ return null;
+ } else {
+// Logger.w(MODULE_NAME, "V2X预警--车辆与事件信息:" +
+// "\n角度:" + eventAngle + " 度" +
+// "\n事件详情:" + v2XRoadEventEntity.getNoveltyInfo().getInfoId()
+// );
+ }
+ } else {
+// Logger.w(MODULE_NAME, "V2X预警--车辆与事件信息:" +
+// "\n距离:" + v2XRoadEventEntity.getDistance() + "米" +
+// "\n事件详情:" + v2XRoadEventEntity.getNoveltyInfo().getInfoId()
+// );
+ }
+ } else {
+// Logger.w(MODULE_NAME,
+// "车头方向: " + currentLocation.getAngle() +
+// "\n事件方向:" + v2XRoadEventEntity.getLocation().getAngle()
+// );
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 疲劳驾驶的展示数据
+ * 分级说明:
+ * 1,驾驶时段 0-2小时为正常状态;
+ * 2,驾驶时段2-3小时为轻度疲劳;
+ * 3,驾驶时段3-4小时为中度疲劳;
+ * 4,驾驶时段4小时以上为重度疲劳;
+ */
+ public static void getFatigueDrivingShow(MogoLocation location, OnFatigueDrivingListener onFatigueDrivingListener) {
+ try {
+ long drivingTime = FatigueDrivingUtils.getDrivingTime();
+ //Logger.i(V2XConst.MODULE_NAME, "车机已经开机: " + drivingTime + " 分钟");
+
+ V2XStrategyPushRes.ResultBean strategyPushEntity =
+ GsonUtil.objectFromJson(SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .getString(V2XConst.V2X_STRATEGY_PUSH), V2XStrategyPushRes.ResultBean.class);
+
+ V2XPushMessageEntity drivingShowEntity = new V2XPushMessageEntity();
+ drivingShowEntity.setSceneId(V2XPoiTypeEnum.ALERT_FATIGUE_DRIVING);
+
+ if (strategyPushEntity != null &&
+ !ArrayUtils.isEmpty(strategyPushEntity.getLevelList())) {
+ for (V2XStrategyPushRes.ResultBean.LevelListBean levelListBean :
+ strategyPushEntity.getLevelList()) {
+ // 找到当前驾驶时常对应的疲劳等级
+ if (drivingTime >= levelListBean.getMinMinute()
+ && drivingTime < levelListBean.getMaxMinute()) {
+ //疲劳等级:NORMAL-正常、SLIGHT-轻度、MODERATE-中度、SEVERE-重度
+ switch (levelListBean.getLevel()) {
+ //正常
+ case "NORMAL":
+ Logger.d(MODULE_NAME, "驾驶疲劳程度: 正常");
+ break;
+ //轻度
+ case "SLIGHT":
+ Logger.w(MODULE_NAME, "驾驶疲劳程度: 轻度");
+ if (!mV2XFatigueDrivingEventLevel.contains("SLIGHT")) {
+ mV2XFatigueDrivingEventLevel.add("SLIGHT");
+ drivingShowEntity.setShowWindow(false);
+ drivingShowEntity.setAlarmContent(levelListBean.getContent());
+ drivingShowEntity.setTts(levelListBean.getTts());
+ drivingShowEntity.setExpireTime(levelListBean.getShowSeconds());
+ // 回调提醒
+ if (onFatigueDrivingListener != null) {
+ onFatigueDrivingListener.onAlarmMessage(drivingShowEntity);
+ }
+ }
+ break;
+ //中度
+ case "MODERATE":
+ Logger.e(MODULE_NAME, "驾驶疲劳程度: 中度");
+ warningParkPoi(location, onFatigueDrivingListener, drivingShowEntity, levelListBean);
+ break;
+ //重度
+ case "SEVERE":
+ Logger.e(MODULE_NAME, "驾驶疲劳程度: 重度");
+ break;
+ default:
+ Logger.e(MODULE_NAME, "驾驶疲劳程度: 超出定义范围");
+ break;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 提醒停车
+ private static void warningParkPoi(MogoLocation location,
+ OnFatigueDrivingListener onFatigueDrivingListener,
+ V2XPushMessageEntity drivingShowEntity,
+ V2XStrategyPushRes.ResultBean.LevelListBean levelListBean) {
+ if (!mV2XFatigueDrivingEventLevel.contains("MODERATE")) {
+ mV2XFatigueDrivingEventLevel.add("MODERATE");
+ // 定位当前位置是否是高速
+ LocationUtils.geoCodeSearch(location, new IMogoGeoSearchListener() {
+ @Override
+ public void onRegeocodeSearched(MogoRegeocodeResult regeocodeResult) {
+ Logger.i(MODULE_NAME, "根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
+ String keyword = "停车场";
+ boolean isHighWay = false;
+ // 如果当前位置是高速则推荐服务区
+ if (regeocodeResult.getRegeocodeAddress().getFormatAddress().contains("高速")) {
+ keyword = "停车场|服务区";
+ isHighWay = true;
+ }
+ MogoPoiSearchQuery poiSearchQuery = new MogoPoiSearchQuery(keyword, keyword);
+ poiSearchQuery.setPageSize(5);
+ poiSearchQuery.setLocation(LocationUtils.getCurrentLatLon());
+ IMogoPoiSearch poiSearch = V2XServiceManager.getMapService().getPoiSearch(V2XUtils.getApp(), poiSearchQuery);
+ boolean finalIsHighWay = isHighWay;
+ poiSearch.setPoiSearchListener(new IMogoPoiSearchListener() {
+ @Override
+ public void onPoiSearched(MogoPoiResult result, int errorCode) {
+ Logger.i(MODULE_NAME, "附近的停车场/服务区:" + GsonUtil.jsonFromObject(result));
+ drivingShowEntity.setAlarmContent(levelListBean.getContent());
+
+ ArrayList pois = result.getPois();
+ if (pois.size() > 0) {
+ MogoPoiItem mogoPoiItem = getFrontPoi(finalIsHighWay, pois, location);
+ Logger.e(MODULE_NAME, "推荐车头前方最近的停车场/服务区:" + GsonUtil.jsonFromObject(mogoPoiItem));
+ if (mogoPoiItem != null) {
+ drivingShowEntity.setExpireTime(levelListBean.getShowSeconds());
+ drivingShowEntity.setShowWindow(true);
+ drivingShowEntity.setTts(levelListBean.getTts());
+ drivingShowEntity.setLon(mogoPoiItem.getPoint().getLon());
+ drivingShowEntity.setLat(mogoPoiItem.getPoint().getLat());
+ drivingShowEntity.setAddress(mogoPoiItem.getTitle());
+ float calculateDistance = Utils.calculateLineDistance(
+ new MogoLatLng(mogoPoiItem.getPoint().getLat(), mogoPoiItem.getPoint().getLon()),
+ LocationUtils.getCurrentLatLon()
+ );
+ drivingShowEntity.setDistance(calculateDistance);
+ } else {
+ drivingShowEntity.setShowWindow(false);
+ drivingShowEntity.setTts(levelListBean.getNoReTts());
+ }
+ } else {
+ drivingShowEntity.setShowWindow(false);
+ drivingShowEntity.setTts(levelListBean.getNoReTts());
+ }
+
+ // 回调提醒
+ if (onFatigueDrivingListener != null) {
+ onFatigueDrivingListener.onAlarmMessage(drivingShowEntity);
+ }
+ }
+
+ @Override
+ public void onPoiItemSearched(MogoPoiItem item, int errorCode) {
+
+ }
+ });
+ poiSearch.searchPOIAsyn();
+ }
+
+ @Override
+ public void onGeocodeSearched(MogoGeocodeResult geocodeResult) {
+
+ }
+ });
+ }
+ }
+
+ public interface OnFatigueDrivingListener {
+ void onAlarmMessage(V2XPushMessageEntity drivingShowEntity);
+ }
+
+
+ // 计算出与车头朝向相同的poi点
+ public static MogoPoiItem getFrontPoi(boolean isHighWay, ArrayList pois, MogoLocation location) {
+ if (location != null && pois != null) {
+ // (高速道路)推荐道路前方180度服务区(限定30公里)
+ // (非高速)推荐停车场(限定5公里内)
+ for (MogoPoiItem poiItem : pois) {
+ // 计算距离
+ float calculateDistance = Utils.calculateLineDistance(
+ new MogoLatLng(poiItem.getPoint().getLat(), poiItem.getPoint().getLon()),
+ LocationUtils.getCurrentLatLon()
+ );
+ Logger.e(MODULE_NAME, "车辆距离POI点距离:" + calculateDistance);
+ Logger.e(MODULE_NAME, "当前车辆是否在高速:" + isHighWay);
+ if (isHighWay) {
+ if (calculateDistance > 100 && calculateDistance < 30000) {
+ // 计算角度
+ double eventAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
+ location.getLongitude(),
+ location.getLatitude(),
+ poiItem.getPoint().getLon(),
+ poiItem.getPoint().getLat(),
+ (int) location.getBearing()
+ );
+ Logger.e(MODULE_NAME, "车辆距离POI角度:" + eventAngle);
+ // 车辆前方180度
+ if (0 <= eventAngle && eventAngle <= 90) {
+ return poiItem;
+ }
+ }
+ } else {
+ if (calculateDistance < 5000) {
+ return poiItem;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 获取车辆的前方的违章停车事件
+ */
+ public static MarkerExploreWay getIllegalParkAlarmEvent(
+ ArrayList v2XExploreWayEntityList,
+ MogoLocation currentLocation) {
+ try {
+ Logger.w(MODULE_NAME, "V2X预警--车辆状态:" + currentLocation);
+ // 60(km/h)
+ if (currentLocation != null && v2XExploreWayEntityList != null) {
+ // 因为集合是按照距离排序后的所以这里检索出来第一个就发出警告
+ for (MarkerExploreWay markerExploreWay : v2XExploreWayEntityList) {
+ // 计算车辆距离
+ float distance = Utils.calculateLineDistance(
+ new MogoLatLng(markerExploreWay.getLocation().getLat(), markerExploreWay.getLocation().getLon()),
+ new MogoLatLng(currentLocation.getLatitude(), currentLocation.getLongitude())
+ );
+
+ Logger.w(MODULE_NAME, "V2X预警--车辆与违章道路信息:" +
+ "\n当前车辆距离违章停车点:" + distance);
+
+ // 判断是否到达了触发距离,50 米
+ if (distance <= 50) {
+ Logger.w(MODULE_NAME, "V2X预警--车辆与违章道路信息:" +
+ "\n违章道路名称:" + markerExploreWay.getAddr() +
+ "\n车头角度:" + currentLocation.getBearing());
+
+ // 判断是否已经提示过道路事件
+ boolean isAlreadyAlert = false;
+ String lastTime = mAlertIllegalParkEventList.get(markerExploreWay);
+ Logger.w(MODULE_NAME,
+ "V2X预警--事件ID:" + markerExploreWay.getInfoId() +
+ "\n上一次预警时间:" + lastTime);
+ if (!TextUtils.isEmpty(lastTime)) {
+ long timeSpan = TimeUtils.getTimeSpanByNow(lastTime, TimeConstants.MIN);
+ Logger.w(MODULE_NAME,
+ "V2X预警--事件ID:" + markerExploreWay.getInfoId() +
+ "\n距离当前时间:" + timeSpan);
+ // 5分钟内不重复提醒
+ if (timeSpan < 5) {
+ isAlreadyAlert = true;
+ }
+ }
+ // 进行提醒
+ if (!isAlreadyAlert) {
+ mAlertIllegalParkEventList.put(markerExploreWay, TimeUtils.getNowString());
+ return markerExploreWay;
+ }
+ return null;
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XCalculateServer.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XCalculateServer.java
new file mode 100644
index 0000000000..e330df3505
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/alarm/V2XCalculateServer.java
@@ -0,0 +1,150 @@
+package com.mogo.module.v2x.alarm;
+
+
+import android.os.Handler;
+
+import com.mogo.map.location.MogoLocation;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XStatusManager;
+import com.mogo.module.v2x.listener.CarStatusListener;
+import com.mogo.utils.logger.Logger;
+
+import java.util.HashMap;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/13 11:02 AM
+ * desc :
+ * 这里充当计算服务
+ * 计算 当前 车速变化回调、方向角度
+ * version: 1.0
+ */
+public class V2XCalculateServer {
+
+ private static final String TAG = "V2XCalculateServer";
+
+ // 当前的车辆位置,主要用 经纬度,角度,速度
+ private static MogoLocation mCurrentLocation;
+
+ // 是否处于停车状态
+ private static boolean mIsPark = true;
+ // 没有行驶的次数
+ private static int mNoDriveCount = 0;
+
+ private static HashMap mCarStatusListener = new HashMap<>();
+ private static V2XCalculateServer mV2XCalculateServer;
+
+ // 一分钟获取一次最新的路况信息
+ private static final int refreshTime = 5_000;
+ private static Handler refreshHandler;
+ private static Runnable refreshRunnable;
+
+ private V2XCalculateServer() {
+ }
+
+ public synchronized static V2XCalculateServer getInstance() {
+ synchronized (V2XCalculateServer.class) {
+ if (mV2XCalculateServer == null) {
+ mV2XCalculateServer = new V2XCalculateServer();
+ if (refreshHandler == null) {
+ refreshHandler = new Handler();
+ }
+ if (refreshRunnable == null) {
+ refreshRunnable = new Runnable() {
+ @Override
+ public void run() {
+ calculateCarStatus();
+ refreshHandler.postDelayed(this, refreshTime);
+ }
+ };
+ }
+ refreshHandler.post(refreshRunnable);
+ }
+ }
+ return mV2XCalculateServer;
+ }
+
+ /**
+ * 添加车辆状态监听
+ *
+ * @param tag 标记
+ * @param carStatusListener 回调
+ */
+ public void addCarStatusListener(String tag, CarStatusListener carStatusListener) {
+ if (mCarStatusListener == null) {
+ mCarStatusListener = new HashMap<>();
+ }
+ mCarStatusListener.put(tag, carStatusListener);
+ }
+
+ /**
+ * 移除指定的标记的回调
+ *
+ * @param tag 标记
+ */
+ public void removeCarStatusListener(String tag) {
+ if (mCarStatusListener != null) {
+ mCarStatusListener.remove(tag);
+ }
+ }
+
+ /**
+ * 记录车辆行驶轨迹
+ *
+ * @param location 车辆位置
+ */
+ public void addCarTrajectory(MogoLocation location) {
+ // 记录最后一次车辆位置信息
+ mCurrentLocation = location;
+ // 车辆状态计算
+ calculateCarStatus();
+ }
+
+ /**
+ * 计算车辆状态
+ */
+ private static void calculateCarStatus() {
+ if (mCurrentLocation != null) {
+ // 获取当前的车速
+ float currentSpeed = mCurrentLocation.getSpeed();
+// Logger.d(V2XConst.MODULE_NAME + "_" + TAG, "车辆状态:" +
+// "\n当前车辆位置->" + V2XStatusManager.getInstance().getLocation().getAddress() +
+// "\ncurrentSpeed 速度->" + currentSpeed +
+// "\n车辆行驶状态mIsPark->" + mIsPark +
+// "\nmNoDriveCount->" + mNoDriveCount);
+
+ // 获取没有车速
+ if (currentSpeed == 0) {
+ // 防止重复播报
+ if (!mIsPark) {
+ // 超过 2 次的速度为 0 ,判定为 行驶->停止
+ if ((++mNoDriveCount) > 2) {
+ if (mCarStatusListener != null) {
+ Logger.d(V2XConst.MODULE_NAME, "车辆状态:车辆从 行驶->停止");
+ mIsPark = true;
+ for (CarStatusListener statusListener : mCarStatusListener.values()) {
+ statusListener.onCarDriving2Stop(mCurrentLocation);
+ }
+ }
+ }
+ }
+ }
+ // 获取到了车速 大于 3m/s = 10公里/小时 判定为行驶状态
+ else if (currentSpeed > 3) {
+ mNoDriveCount = 0;
+ if (mIsPark) {
+ if (mCarStatusListener != null) {
+ Logger.d(V2XConst.MODULE_NAME, "车辆状态:车辆从 停止->行驶");
+ mIsPark = false;
+ for (CarStatusListener statusListener : mCarStatusListener.values()) {
+ statusListener.onCarStop2Driving(mCurrentLocation);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XAlarmEventRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XAlarmEventRes.java
new file mode 100644
index 0000000000..2e2b2a1a3f
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XAlarmEventRes.java
@@ -0,0 +1,280 @@
+
+package com.mogo.module.v2x.entity.net;
+
+import android.text.TextUtils;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import com.mogo.commons.data.BaseData;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerOnlineCar;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+@SuppressWarnings("unused")
+public class V2XAlarmEventRes extends BaseData implements Serializable {
+ @Expose
+ private Result result;
+
+ public Result getResult() {
+ return result;
+ }
+
+ public void setResult(Result result) {
+ this.result = result;
+ }
+
+ public class Result {
+ @Expose
+ @SerializedName(value = "recommendInfo", alternate = {"alarmInfo"})
+ private AlarmInfo alarmInfo;
+ @Expose
+ private ArrayList onlineCar;
+
+ public ArrayList getOnlineCar() {
+ return onlineCar;
+ }
+
+ public void setOnlineCar(ArrayList onlineCar) {
+ this.onlineCar = onlineCar;
+ }
+
+ public AlarmInfo getAlarmInfo() {
+ return alarmInfo;
+ }
+
+ public void setAlarmInfo(AlarmInfo alarmInfo) {
+ this.alarmInfo = alarmInfo;
+ }
+
+ @Override
+ public String toString() {
+ return "Result{" +
+ "alarmInfo=" + alarmInfo +
+ ", onlineCar=" + onlineCar +
+ '}';
+ }
+
+ }
+
+ public static class AlarmInfo {
+
+ @Expose
+ private ContentData contentData;
+ @Expose
+ private Double distance;
+ @Expose
+ private MarkerLocation location;
+ @Expose
+ private String poiType;
+ @Expose
+ private String tts;
+ @Expose
+ private String type;
+ @Expose
+ private String alarmContent;
+ @Expose
+ private int expireTime;
+ @Expose
+ private int parkingSpaceSurplusNum;
+
+ public ContentData getContentData() {
+ return contentData;
+ }
+
+ public void setContentData(ContentData contentData) {
+ this.contentData = contentData;
+ }
+
+ public Double getDistance() {
+ return distance;
+ }
+
+ public void setDistance(Double distance) {
+ this.distance = distance;
+ }
+
+ public MarkerLocation getLocation() {
+ return location;
+ }
+
+ public void setLocation(MarkerLocation location) {
+ this.location = location;
+ }
+
+ public String getPoiType() {
+ if (TextUtils.isEmpty(poiType)) {
+ return "";
+ }
+ return poiType;
+ }
+
+ public void setPoiType(String poiType) {
+ this.poiType = poiType;
+ }
+
+ public String getTts() {
+ if (TextUtils.isEmpty(tts)) {
+ return "";
+ }
+ return tts;
+ }
+
+ public void setTts(String tts) {
+ this.tts = tts;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getAlarmContent() {
+ return alarmContent;
+ }
+
+ public void setAlarmContent(String alarmContent) {
+ this.alarmContent = alarmContent;
+ }
+
+ public int getExpireTime() {
+ return expireTime;
+ }
+
+ public void setExpireTime(int expireTime) {
+ this.expireTime = expireTime;
+ }
+
+ public int getParkingSpaceSurplusNum() {
+ return parkingSpaceSurplusNum;
+ }
+
+ public void setParkingSpaceSurplusNum(int parkingSpaceSurplusNum) {
+ this.parkingSpaceSurplusNum = parkingSpaceSurplusNum;
+ }
+
+ @Override
+ public String toString() {
+ return "AlarmInfo{" +
+ "contentData=" + contentData +
+ ", distance=" + distance +
+ ", location=" + location +
+ ", poiType='" + poiType + '\'' +
+ ", tts='" + tts + '\'' +
+ ", type='" + type + '\'' +
+ ", alarmContent='" + alarmContent + '\'' +
+ ", expireTime=" + expireTime +
+ ", parkingSpaceSurplusNum=" + parkingSpaceSurplusNum +
+ '}';
+ }
+ }
+
+ public class ContentData {
+
+ @Expose
+ private String iconUrl;
+ @Expose
+ private String imgUrl;
+ @Expose
+ private String infoId = ""; // POI 唯一标示 「纠错」或「确认」「点赞」使用
+ @Expose
+ private String title;
+ @Expose
+ private String content;
+ @Expose
+ private String gasPrices;//"[{\"gasCode\":\"95\",\"gasPrice\":10.0},{\"gasCode\":\"98\",\"gasPrice\":23.0}]"
+ @Expose
+ private String styleType;// 内容类型,image-图片类型,video-视频类型
+ @Expose
+ private String carSn;// 如果是用户上报的,则需要返回该字段
+
+ public String getIconUrl() {
+ return iconUrl;
+ }
+
+ public void setIconUrl(String iconUrl) {
+ this.iconUrl = iconUrl;
+ }
+
+ public String getImgUrl() {
+ return imgUrl;
+ }
+
+ public void setImgUrl(String imgUrl) {
+ this.imgUrl = imgUrl;
+ }
+
+ public String getInfoId() {
+ return infoId;
+ }
+
+ public void setInfoId(String infoId) {
+ this.infoId = infoId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getGasPrices() {
+ return gasPrices;
+ }
+
+ public void setGasPrices(String gasPrices) {
+ this.gasPrices = gasPrices;
+ }
+
+ public String getStyleType() {
+ return styleType;
+ }
+
+ public void setStyleType(String styleType) {
+ this.styleType = styleType;
+ }
+
+ public String getCarSn() {
+ return carSn;
+ }
+
+ public void setCarSn(String carSn) {
+ this.carSn = carSn;
+ }
+
+ @Override
+ public String toString() {
+ return "ContentData{" +
+ "iconUrl='" + iconUrl + '\'' +
+ ", imgUrl='" + imgUrl + '\'' +
+ ", infoId='" + infoId + '\'' +
+ ", title='" + title + '\'' +
+ ", content='" + content + '\'' +
+ ", gasPrices='" + gasPrices + '\'' +
+ ", styleType='" + styleType + '\'' +
+ ", carSn='" + carSn + '\'' +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "V2XAlarmEventMessage{" +
+ "result=" + result +
+ '}';
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XDemoUserInfoRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XDemoUserInfoRes.java
new file mode 100644
index 0000000000..6413f75f40
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XDemoUserInfoRes.java
@@ -0,0 +1,258 @@
+package com.mogo.module.v2x.entity.net;
+
+import com.mogo.commons.data.BaseData;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 4:20 PM
+ * desc : TODO 前瞻需求演示使用的用户数据
+ * version: 1.0
+ */
+public class V2XDemoUserInfoRes extends BaseData implements Serializable {
+
+ /**
+ * code : 0
+ * msg :
+ * detailMsg :
+ * result : {"userList":[{"sceneType":"1","location":{"lat":39.97541,"lon":116.41782761},"userInfo":{"sn":"ZD801B1920L00818","userId":1,"userName":"用户昵称","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","gender":"男","age":20,"lastActiveweekAvgscore":"96","safeLabel":"老司机","safeLabelType":1}},{"sceneType":"2","location":{"lat":39.97541,"lon":116.41782761},"userInfo":{"sn":"ZD802B1932L00779","userId":1,"userName":"用户昵称","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","gender":"男","age":20,"lastActiveweekAvgscore":"96","safeLabel":"老司机","safeLabelType":1}},{"sceneType":"3","location":{"lat":39.97541,"lon":116.41782761},"userInfo":{"sn":"ZD802B1932L00779","userId":1,"userName":"用户昵称","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","gender":"男","age":20,"lastActiveweekAvgscore":"96","safeLabel":"老司机","safeLabelType":1}}]}
+ */
+
+ private ResultBean result;
+
+ 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 ResultBean getResult() {
+ return result;
+ }
+
+ public void setResult(ResultBean result) {
+ this.result = result;
+ }
+
+ public static class ResultBean {
+ private List userList;
+
+ public List getUserList() {
+ return userList;
+ }
+
+ public void setUserList(List userList) {
+ this.userList = userList;
+ }
+
+ public static class UserListBean {
+ /**
+ * sceneType : 1
+ * location : {"lat":39.97541,"lon":116.41782761}
+ * userInfo : {"sn":"ZD801B1920L00818","userId":1,"userName":"用户昵称","userHead":"https://www.baidu.com/img/baidu_jgylogo3.png","gender":"男","age":20,"lastActiveweekAvgscore":"96","safeLabel":"老司机","safeLabelType":1}
+ */
+
+ private String sceneType;
+ private LocationBean location;
+ private UserInfoBean userInfo;
+
+ public String getSceneType() {
+ return sceneType;
+ }
+
+ public void setSceneType(String sceneType) {
+ this.sceneType = sceneType;
+ }
+
+ public LocationBean getLocation() {
+ return location;
+ }
+
+ public void setLocation(LocationBean location) {
+ this.location = location;
+ }
+
+ public UserInfoBean getUserInfo() {
+ return userInfo;
+ }
+
+ public void setUserInfo(UserInfoBean userInfo) {
+ this.userInfo = userInfo;
+ }
+
+ public static class LocationBean {
+ /**
+ * lat : 39.97541
+ * lon : 116.41782761
+ */
+
+ private double lat;
+ private double lon;
+
+ public double getLat() {
+ return lat;
+ }
+
+ public void setLat(double lat) {
+ this.lat = lat;
+ }
+
+ public double getLon() {
+ return lon;
+ }
+
+ public void setLon(double lon) {
+ this.lon = lon;
+ }
+
+ @Override
+ public String toString() {
+ return "LocationBean{" +
+ "lat=" + lat +
+ ", lon=" + lon +
+ '}';
+ }
+ }
+
+ public static class UserInfoBean {
+ /**
+ * sn : ZD801B1920L00818
+ * userId : 1
+ * userName : 用户昵称
+ * userHead : https://www.baidu.com/img/baidu_jgylogo3.png
+ * gender : 男
+ * age : 20
+ * lastActiveweekAvgscore : 96
+ * safeLabel : 老司机
+ * safeLabelType : 1
+ */
+
+ private String sn;
+ private int userId;
+ private String userName;
+ private String userHead;
+ private String gender;
+ private int age;
+ private String lastActiveweekAvgscore;
+ private String safeLabel;
+ private int safeLabelType;
+
+ public String getSn() {
+ return sn;
+ }
+
+ public void setSn(String sn) {
+ this.sn = sn;
+ }
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public void setUserId(int userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getUserHead() {
+ return userHead;
+ }
+
+ public void setUserHead(String userHead) {
+ this.userHead = userHead;
+ }
+
+ public String getGender() {
+ return gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getLastActiveweekAvgscore() {
+ return lastActiveweekAvgscore;
+ }
+
+ public void setLastActiveweekAvgscore(String lastActiveweekAvgscore) {
+ this.lastActiveweekAvgscore = lastActiveweekAvgscore;
+ }
+
+ public String getSafeLabel() {
+ return safeLabel;
+ }
+
+ public void setSafeLabel(String safeLabel) {
+ this.safeLabel = safeLabel;
+ }
+
+ public int getSafeLabelType() {
+ return safeLabelType;
+ }
+
+ public void setSafeLabelType(int safeLabelType) {
+ this.safeLabelType = safeLabelType;
+ }
+
+ @Override
+ public String toString() {
+ return "UserInfoBean{" +
+ "sn='" + sn + '\'' +
+ ", userId=" + userId +
+ ", userName='" + userName + '\'' +
+ ", userHead='" + userHead + '\'' +
+ ", gender='" + gender + '\'' +
+ ", age=" + age +
+ ", lastActiveweekAvgscore='" + lastActiveweekAvgscore + '\'' +
+ ", safeLabel='" + safeLabel + '\'' +
+ ", safeLabelType=" + safeLabelType +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "UserListBean{" +
+ "sceneType='" + sceneType + '\'' +
+ ", location=" + location +
+ ", userInfo=" + userInfo +
+ '}';
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "V2XDemoUserInfoEntity{" +
+ "result=" + result +
+ '}';
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XGiveLike.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XGiveLike.java
new file mode 100644
index 0000000000..9b6e16990b
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XGiveLike.java
@@ -0,0 +1,52 @@
+
+package com.mogo.module.v2x.entity.net;
+
+import com.google.gson.annotations.Expose;
+
+import java.io.Serializable;
+
+@SuppressWarnings("unused")
+public class V2XGiveLike implements Serializable {
+
+ @Expose
+ private Long code;
+ @Expose
+ private String msg;
+ @Expose
+ private String result;
+ @Expose
+ private String sign;
+
+ public Long getCode() {
+ return code;
+ }
+
+ public void setCode(Long code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public String getResult() {
+ return result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ public String getSign() {
+ return sign;
+ }
+
+ public void setSign(String sign) {
+ this.sign = sign;
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarBroadcastReq.kt b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarBroadcastReq.kt
new file mode 100644
index 0000000000..da482ace67
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarBroadcastReq.kt
@@ -0,0 +1,25 @@
+package com.mogo.module.v2x.entity.net
+
+/**
+ * 直播心跳请求
+ */
+class V2XLiveCarBroadcastReq {
+
+ var eventId: String? = null
+ var sn: String
+ var type: Int = 0
+ var videoChannel: String
+
+ constructor(sn: String, videoChannel: String) {
+ this.sn = sn
+ this.videoChannel = videoChannel
+ }
+
+ constructor(eventId: String, sn: String, type: Int, videoChannel: String) {
+ this.eventId = eventId
+ this.sn = sn
+ this.type = type
+ this.videoChannel = videoChannel
+ }
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarRes.java
new file mode 100644
index 0000000000..14fe86261e
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLiveCarRes.java
@@ -0,0 +1,56 @@
+package com.mogo.module.v2x.entity.net;
+
+import com.google.gson.annotations.Expose;
+import com.mogo.commons.data.BaseData;
+import com.mogo.module.common.entity.V2XLiveCarInfoEntity;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/14 2:58 PM
+ * desc : 根据经纬度查询附近可直播车机直播信息
+ * version: 1.0
+ */
+public class V2XLiveCarRes extends BaseData implements Serializable {
+ @Expose
+ private ResultBean result;
+
+ public static class ResultBean {
+
+ private List info;
+
+ public List getInfo() {
+ return info;
+ }
+
+ public void setInfo(List info) {
+ this.info = info;
+ }
+
+ @Override
+ public String toString() {
+ return "ResultBean{" +
+ "info=" + info +
+ '}';
+ }
+ }
+
+ public ResultBean getResult() {
+ return result;
+ }
+
+ public void setResult(ResultBean result) {
+ this.result = result;
+ }
+
+ @Override
+ public String toString() {
+ return "V2XLiveCarRes{" +
+ "result=" + result +
+ '}';
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLivePushVoRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLivePushVoRes.java
new file mode 100644
index 0000000000..d0bc3fa292
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XLivePushVoRes.java
@@ -0,0 +1,113 @@
+package com.mogo.module.v2x.entity.net;
+
+import com.mogo.commons.data.BaseData;
+
+import java.io.Serializable;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/16 1:43 PM
+ * desc : 推流与停止推流接口
+ * version: 1.0
+ */
+public class V2XLivePushVoRes extends BaseData implements Serializable {
+ public V2XLivePushVoEntity result;
+
+ public V2XLivePushVoEntity getResult() {
+ return result;
+ }
+
+ public void setResult(V2XLivePushVoEntity result) {
+ this.result = result;
+ }
+
+ @Override
+ public String toString() {
+ return "V2XLivePushVoRes{" +
+ "result=" + result +
+ ", code=" + code +
+ ", msg='" + msg + '\'' +
+ '}';
+ }
+
+ public class V2XLivePushVoEntity {
+ private String livePlayUrl;
+ private PlayUrl playUrl;
+ private String videoChannel;
+
+ public String getLivePlayUrl() {
+ return livePlayUrl;
+ }
+
+ public void setLivePlayUrl(String livePlayUrl) {
+ this.livePlayUrl = livePlayUrl;
+ }
+
+ public PlayUrl getPlayUrl() {
+ return playUrl;
+ }
+
+ public void setPlayUrl(PlayUrl playUrl) {
+ this.playUrl = playUrl;
+ }
+
+ public String getVideoChannel() {
+ return videoChannel;
+ }
+
+ public void setVideoChannel(String videoChannel) {
+ this.videoChannel = videoChannel;
+ }
+
+ public class PlayUrl {
+
+ private String flv;
+ private String hls;
+ private String rtmp;
+
+ public String getFlv() {
+ return flv;
+ }
+
+ public void setFlv(String flv) {
+ this.flv = flv;
+ }
+
+ public String getHls() {
+ return hls;
+ }
+
+ public void setHls(String hls) {
+ this.hls = hls;
+ }
+
+ public String getRtmp() {
+ return rtmp;
+ }
+
+ public void setRtmp(String rtmp) {
+ this.rtmp = rtmp;
+ }
+
+ @Override
+ public String toString() {
+ return "PlayUrl{" +
+ "flv='" + flv + '\'' +
+ ", hls='" + hls + '\'' +
+ ", rtmp='" + rtmp + '\'' +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "V2XLivePushVoEntity{" +
+ "livePlayUrl='" + livePlayUrl + '\'' +
+ ", playUrl=" + playUrl +
+ ", videoChannel='" + videoChannel + '\'' +
+ '}';
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSeekHelpRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSeekHelpRes.java
new file mode 100644
index 0000000000..705615b72b
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSeekHelpRes.java
@@ -0,0 +1,52 @@
+package com.mogo.module.v2x.entity.net;
+
+import com.mogo.commons.data.BaseData;
+
+import java.io.Serializable;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/3/11 4:25 PM
+ * desc : 故障求助查询,当前车辆是否处于求助中
+ * version: 1.0
+ */
+public class V2XSeekHelpRes extends BaseData implements Serializable {
+ private ResultBean result;
+
+ public ResultBean getResult() {
+ return result;
+ }
+
+ public void setResult(ResultBean result) {
+ this.result = result;
+ }
+
+ public static class ResultBean {
+ private int vehicleType;
+
+ public int getVehicleType() {
+ return vehicleType;
+ }
+
+ public void setVehicleType(int vehicleType) {
+ this.vehicleType = vehicleType;
+ }
+
+ @Override
+ public String toString() {
+ return "ResultBean{" +
+ "vehicleType=" + vehicleType +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "V2XSeekHelpResult{" +
+ "result=" + result +
+ ", code=" + code +
+ ", msg='" + msg + '\'' +
+ '}';
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSpecialCarRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSpecialCarRes.java
new file mode 100644
index 0000000000..9ffc90ca91
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XSpecialCarRes.java
@@ -0,0 +1,205 @@
+
+package com.mogo.module.v2x.entity.net;
+
+import java.io.Serializable;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class V2XSpecialCarRes implements Serializable {
+
+ private List coordinates;
+
+ public List getCoordinates() {
+ return coordinates;
+ }
+
+ public void setCoordinates(List coordinates) {
+ this.coordinates = coordinates;
+ }
+
+ @Override
+ public String toString() {
+ return "V2XMarkerResult{" +
+ "coordinates=" + coordinates +
+ '}';
+ }
+
+ public class V2XMarkerEntity implements Serializable {
+
+ /**
+ * createTime : 1587111513507
+ * distance : 100
+ * lat : 39.96911187
+ * lon : 116.41777396
+ * sn : ZD802B1932L00681
+ * targetId : 20007
+ * targetName : 故障车
+ * userInfo : {"age":33,"displayName":"飞","headImgUrl":"http://img.zhidaohulian.com/fileServer/api/qa/user_info/1068057333299/67933ffb9a7e237c8cc2d8d9f66efcd0.jpg","sex":1,"sn":"ZD801B1920L00568","userId":1068057333299}
+ */
+
+ private long createTime;
+ private int distance;
+ private double lat;
+ private double lon;
+ private String sn;
+ private int targetId;
+ private String targetName;
+ private V2XMarkerEntity.UserInfoBean userInfo;
+
+ public long getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(long createTime) {
+ this.createTime = createTime;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public void setDistance(int distance) {
+ this.distance = distance;
+ }
+
+ public double getLat() {
+ return lat;
+ }
+
+ public void setLat(double lat) {
+ this.lat = lat;
+ }
+
+ public double getLon() {
+ return lon;
+ }
+
+ public void setLon(double lon) {
+ this.lon = lon;
+ }
+
+ public String getSn() {
+ return sn;
+ }
+
+ public void setSn(String sn) {
+ this.sn = sn;
+ }
+
+ public int getTargetId() {
+ return targetId;
+ }
+
+ public void setTargetId(int targetId) {
+ this.targetId = targetId;
+ }
+
+ public String getTargetName() {
+ return targetName;
+ }
+
+ public void setTargetName(String targetName) {
+ this.targetName = targetName;
+ }
+
+ public V2XMarkerEntity.UserInfoBean getUserInfo() {
+ return userInfo;
+ }
+
+ public void setUserInfo(V2XMarkerEntity.UserInfoBean userInfo) {
+ this.userInfo = userInfo;
+ }
+
+ public class UserInfoBean implements Serializable {
+ /**
+ * age : 33
+ * displayName : 飞
+ * headImgUrl : http://img.zhidaohulian.com/fileServer/api/qa/user_info/1068057333299/67933ffb9a7e237c8cc2d8d9f66efcd0.jpg
+ * sex : 1
+ * sn : ZD801B1920L00568
+ * userId : 1068057333299
+ */
+
+ private int age;
+ private String displayName;
+ private String headImgUrl;
+ private int sex;
+ private String sn;
+ private long userId;
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getHeadImgUrl() {
+ return headImgUrl;
+ }
+
+ public void setHeadImgUrl(String headImgUrl) {
+ this.headImgUrl = headImgUrl;
+ }
+
+ public int getSex() {
+ return sex;
+ }
+
+ public void setSex(int sex) {
+ this.sex = sex;
+ }
+
+ public String getSn() {
+ return sn;
+ }
+
+ public void setSn(String sn) {
+ this.sn = sn;
+ }
+
+ public long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(long userId) {
+ this.userId = userId;
+ }
+
+ @Override
+ public String toString() {
+ return "UserInfoBean{" +
+ "age=" + age +
+ ", displayName='" + displayName + '\'' +
+ ", headImgUrl='" + headImgUrl + '\'' +
+ ", sex=" + sex +
+ ", sn='" + sn + '\'' +
+ ", userId=" + userId +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "V2XMarkerEntity{" +
+ "createTime=" + createTime +
+ ", distance=" + distance +
+ ", lat=" + lat +
+ ", lon=" + lon +
+ ", sn='" + sn + '\'' +
+ ", targetId=" + targetId +
+ ", targetName='" + targetName + '\'' +
+ ", userInfo=" + userInfo +
+ '}';
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XStrategyPushRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XStrategyPushRes.java
new file mode 100644
index 0000000000..250c4131b7
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XStrategyPushRes.java
@@ -0,0 +1,253 @@
+package com.mogo.module.v2x.entity.net;
+
+import com.mogo.commons.data.BaseData;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/26 2:30 PM
+ * desc : 疲劳驾驶提醒策略
+ * version: 1.0
+ */
+public class V2XStrategyPushRes extends BaseData implements Serializable {
+
+ /**
+ * result : {"levelList":[{"level":"NORMAL","minMinute":0,"maxMinute":120},{"content":"已连续驾驶2小时,请注意休息","level":"SLIGHT","tts":"已连续驾驶2小时,听歌可以缓解疲劳,可以对我说打开音乐","showSeconds":15,"minMinute":120,"maxMinute":180},{"content":"已连续驾驶3小时,请注意停车休息","highSpeed":{"recommend":"REST_AREA","direction":"FRONT","angle":180,"distance":30},"level":"MODERATE","lowSpeed":{"recommend":"PARK","direction":"FRONT","angle":180,"distance":5},"tts":"已连续驾驶3小时,已为您找到附近服务区/停车场,请停车休息,可以对我说导航前往","showSeconds":20,"noReTts":"已连续驾驶3小时,为避免事故发生,请尽快进入停车区休息","minMinute":180,"maxMinute":240}],"drivingIgnoreMinutes":20,"restIgnoreMinutes":20}
+ */
+ private ResultBean result;
+
+ public ResultBean getResult() {
+ return result;
+ }
+
+ public void setResult(ResultBean result) {
+ this.result = result;
+ }
+
+ public static class ResultBean {
+ /**
+ * levelList : [{"level":"NORMAL","minMinute":0,"maxMinute":120},{"content":"已连续驾驶2小时,请注意休息","level":"SLIGHT","tts":"已连续驾驶2小时,听歌可以缓解疲劳,可以对我说打开音乐","showSeconds":15,"minMinute":120,"maxMinute":180},{"content":"已连续驾驶3小时,请注意停车休息","highSpeed":{"recommend":"REST_AREA","direction":"FRONT","angle":180,"distance":30},"level":"MODERATE","lowSpeed":{"recommend":"PARK","direction":"FRONT","angle":180,"distance":5},"tts":"已连续驾驶3小时,已为您找到附近服务区/停车场,请停车休息,可以对我说导航前往","showSeconds":20,"noReTts":"已连续驾驶3小时,为避免事故发生,请尽快进入停车区休息","minMinute":180,"maxMinute":240}]
+ * drivingIgnoreMinutes : 20
+ * restIgnoreMinutes : 20
+ */
+
+ private int drivingIgnoreMinutes;
+ private int restIgnoreMinutes;
+ private List levelList;
+
+ public int getDrivingIgnoreMinutes() {
+ return drivingIgnoreMinutes;
+ }
+
+ public void setDrivingIgnoreMinutes(int drivingIgnoreMinutes) {
+ this.drivingIgnoreMinutes = drivingIgnoreMinutes;
+ }
+
+ public int getRestIgnoreMinutes() {
+ return restIgnoreMinutes;
+ }
+
+ public void setRestIgnoreMinutes(int restIgnoreMinutes) {
+ this.restIgnoreMinutes = restIgnoreMinutes;
+ }
+
+ public List getLevelList() {
+ return levelList;
+ }
+
+ public void setLevelList(List levelList) {
+ this.levelList = levelList;
+ }
+
+ public static class LevelListBean {
+ /**
+ * level : NORMAL
+ * minMinute : 0
+ * maxMinute : 120
+ * content : 已连续驾驶2小时,请注意休息
+ * tts : 已连续驾驶2小时,听歌可以缓解疲劳,可以对我说打开音乐
+ * showSeconds : 15
+ * highSpeed : {"recommend":"REST_AREA","direction":"FRONT","angle":180,"distance":30}
+ * lowSpeed : {"recommend":"PARK","direction":"FRONT","angle":180,"distance":5}
+ * noReTts : 已连续驾驶3小时,为避免事故发生,请尽快进入停车区休息
+ */
+
+ private String level;
+ private int minMinute;
+ private int maxMinute;
+ private String content;
+ private String tts;
+ private int showSeconds;
+ private HighSpeedBean highSpeed;
+ private LowSpeedBean lowSpeed;
+ private String noReTts;
+
+ public String getLevel() {
+ return level;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public int getMinMinute() {
+ return minMinute;
+ }
+
+ public void setMinMinute(int minMinute) {
+ this.minMinute = minMinute;
+ }
+
+ public int getMaxMinute() {
+ return maxMinute;
+ }
+
+ public void setMaxMinute(int maxMinute) {
+ this.maxMinute = maxMinute;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getTts() {
+ return tts;
+ }
+
+ public void setTts(String tts) {
+ this.tts = tts;
+ }
+
+ public int getShowSeconds() {
+ return showSeconds;
+ }
+
+ public void setShowSeconds(int showSeconds) {
+ this.showSeconds = showSeconds;
+ }
+
+ public HighSpeedBean getHighSpeed() {
+ return highSpeed;
+ }
+
+ public void setHighSpeed(HighSpeedBean highSpeed) {
+ this.highSpeed = highSpeed;
+ }
+
+ public LowSpeedBean getLowSpeed() {
+ return lowSpeed;
+ }
+
+ public void setLowSpeed(LowSpeedBean lowSpeed) {
+ this.lowSpeed = lowSpeed;
+ }
+
+ public String getNoReTts() {
+ return noReTts;
+ }
+
+ public void setNoReTts(String noReTts) {
+ this.noReTts = noReTts;
+ }
+
+ public static class HighSpeedBean {
+ /**
+ * recommend : REST_AREA
+ * direction : FRONT
+ * angle : 180
+ * distance : 30
+ */
+
+ private String recommend;
+ private String direction;
+ private int angle;
+ private int distance;
+
+ public String getRecommend() {
+ return recommend;
+ }
+
+ public void setRecommend(String recommend) {
+ this.recommend = recommend;
+ }
+
+ public String getDirection() {
+ return direction;
+ }
+
+ public void setDirection(String direction) {
+ this.direction = direction;
+ }
+
+ public int getAngle() {
+ return angle;
+ }
+
+ public void setAngle(int angle) {
+ this.angle = angle;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public void setDistance(int distance) {
+ this.distance = distance;
+ }
+ }
+
+ public static class LowSpeedBean {
+ /**
+ * recommend : PARK
+ * direction : FRONT
+ * angle : 180
+ * distance : 5
+ */
+
+ private String recommend;
+ private String direction;
+ private int angle;
+ private int distance;
+
+ public String getRecommend() {
+ return recommend;
+ }
+
+ public void setRecommend(String recommend) {
+ this.recommend = recommend;
+ }
+
+ public String getDirection() {
+ return direction;
+ }
+
+ public void setDirection(String direction) {
+ this.direction = direction;
+ }
+
+ public int getAngle() {
+ return angle;
+ }
+
+ public void setAngle(int angle) {
+ this.angle = angle;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public void setDistance(int distance) {
+ this.distance = distance;
+ }
+ }
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XUserInfoRes.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XUserInfoRes.java
new file mode 100644
index 0000000000..bc5a567ec6
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/entity/net/V2XUserInfoRes.java
@@ -0,0 +1,344 @@
+
+package com.mogo.module.v2x.entity.net;
+
+import com.google.gson.annotations.Expose;
+import com.mogo.commons.data.BaseData;
+
+import java.io.Serializable;
+
+public class V2XUserInfoRes extends BaseData implements Serializable {
+
+ @Expose
+ private Result result;
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public Result getResult() {
+ return result;
+ }
+
+ public void setResult(Result result) {
+ this.result = result;
+ }
+
+ public class Result {
+
+ @Expose
+ private Info info;
+
+ public Info getInfo() {
+ return info;
+ }
+
+ public void setInfo(Info info) {
+ this.info = info;
+ }
+
+
+ public class Info {
+
+ @Expose
+ private Long activeStatus;
+ @Expose
+ private Long bindStatus;
+ @Expose
+ private String bindType;
+ @Expose
+ private String bindUserId;
+ @Expose
+ private String erpSnGroup;
+ @Expose
+ private String erpSnType;
+ @Expose
+ private String iccid;
+ @Expose
+ private String ifCarcorder;
+ @Expose
+ private String ifImdemo;
+ @Expose
+ private String ifSocketservice;
+ @Expose
+ private String lastActiveCity;
+ @Expose
+ private Long lastBrandId;
+ @Expose
+ private String lastBrandName;
+ @Expose
+ private String lastCarNum;
+ @Expose
+ private String lastCarNumEn;
+ @Expose
+ private String lastFortaVersion;
+ @Expose
+ private Long lastModelId;
+ @Expose
+ private String lastModelName;
+ @Expose
+ private String sn;
+ @Expose
+ private String snGroupDetail;
+ @Expose
+ private String songTypeTop2;
+ @Expose
+ private String userNickName;
+ @Expose
+ private String cardIdAge;
+ @Expose
+ private String headImgUrl;
+ @Expose
+ private String cardIdSex;
+
+ public String getHeadImgUrl() {
+ return headImgUrl;
+ }
+
+ public void setHeadImgUrl(String headImgUrl) {
+ this.headImgUrl = headImgUrl;
+ }
+
+ public String getCardIdSex() {
+ return cardIdSex;
+ }
+
+ public void setCardIdSex(String cardIdSex) {
+ this.cardIdSex = cardIdSex;
+ }
+
+ public String getCardIdAge() {
+ return cardIdAge;
+ }
+
+ public void setCardIdAge(String cardIdAge) {
+ this.cardIdAge = cardIdAge;
+ }
+
+ public Long getActiveStatus() {
+ return activeStatus;
+ }
+
+ public void setActiveStatus(Long activeStatus) {
+ this.activeStatus = activeStatus;
+ }
+
+ public Long getBindStatus() {
+ return bindStatus;
+ }
+
+ public void setBindStatus(Long bindStatus) {
+ this.bindStatus = bindStatus;
+ }
+
+ public String getBindType() {
+ return bindType;
+ }
+
+ public void setBindType(String bindType) {
+ this.bindType = bindType;
+ }
+
+ public String getBindUserId() {
+ return bindUserId;
+ }
+
+ public void setBindUserId(String bindUserId) {
+ this.bindUserId = bindUserId;
+ }
+
+ @Override
+ public String toString() {
+ return "Info{" +
+ "activeStatus=" + activeStatus +
+ ", bindStatus=" + bindStatus +
+ ", bindType='" + bindType + '\'' +
+ ", bindUserId='" + bindUserId + '\'' +
+ ", erpSnGroup='" + erpSnGroup + '\'' +
+ ", erpSnType='" + erpSnType + '\'' +
+ ", iccid='" + iccid + '\'' +
+ ", ifCarcorder='" + ifCarcorder + '\'' +
+ ", ifImdemo='" + ifImdemo + '\'' +
+ ", ifSocketservice='" + ifSocketservice + '\'' +
+ ", lastActiveCity='" + lastActiveCity + '\'' +
+ ", lastBrandId=" + lastBrandId +
+ ", lastBrandName='" + lastBrandName + '\'' +
+ ", lastCarNum='" + lastCarNum + '\'' +
+ ", lastCarNumEn='" + lastCarNumEn + '\'' +
+ ", lastFortaVersion='" + lastFortaVersion + '\'' +
+ ", lastModelId=" + lastModelId +
+ ", lastModelName='" + lastModelName + '\'' +
+ ", sn='" + sn + '\'' +
+ ", snGroupDetail='" + snGroupDetail + '\'' +
+ ", songTypeTop2='" + songTypeTop2 + '\'' +
+ ", userNickName='" + userNickName + '\'' +
+ ", cardIdAge='" + cardIdAge + '\'' +
+ ", headImgUrl='" + headImgUrl + '\'' +
+ ", cardIdSex='" + cardIdSex + '\'' +
+ '}';
+ }
+
+ public String getErpSnGroup() {
+ return erpSnGroup;
+ }
+
+ public void setErpSnGroup(String erpSnGroup) {
+ this.erpSnGroup = erpSnGroup;
+ }
+
+ public String getErpSnType() {
+ return erpSnType;
+ }
+
+ public void setErpSnType(String erpSnType) {
+ this.erpSnType = erpSnType;
+ }
+
+ public String getIccid() {
+ return iccid;
+ }
+
+ public void setIccid(String iccid) {
+ this.iccid = iccid;
+ }
+
+ public String getIfCarcorder() {
+ return ifCarcorder;
+ }
+
+ public void setIfCarcorder(String ifCarcorder) {
+ this.ifCarcorder = ifCarcorder;
+ }
+
+ public String getIfImdemo() {
+ return ifImdemo;
+ }
+
+ public void setIfImdemo(String ifImdemo) {
+ this.ifImdemo = ifImdemo;
+ }
+
+ public String getIfSocketservice() {
+ return ifSocketservice;
+ }
+
+ public void setIfSocketservice(String ifSocketservice) {
+ this.ifSocketservice = ifSocketservice;
+ }
+
+ public String getLastActiveCity() {
+ return lastActiveCity;
+ }
+
+ public void setLastActiveCity(String lastActiveCity) {
+ this.lastActiveCity = lastActiveCity;
+ }
+
+ public Long getLastBrandId() {
+ return lastBrandId;
+ }
+
+ public void setLastBrandId(Long lastBrandId) {
+ this.lastBrandId = lastBrandId;
+ }
+
+ public String getLastBrandName() {
+ return lastBrandName;
+ }
+
+ public void setLastBrandName(String lastBrandName) {
+ this.lastBrandName = lastBrandName;
+ }
+
+ public String getLastCarNum() {
+ return lastCarNum;
+ }
+
+ public void setLastCarNum(String lastCarNum) {
+ this.lastCarNum = lastCarNum;
+ }
+
+ public String getLastCarNumEn() {
+ return lastCarNumEn;
+ }
+
+ public void setLastCarNumEn(String lastCarNumEn) {
+ this.lastCarNumEn = lastCarNumEn;
+ }
+
+ public String getLastFortaVersion() {
+ return lastFortaVersion;
+ }
+
+ public void setLastFortaVersion(String lastFortaVersion) {
+ this.lastFortaVersion = lastFortaVersion;
+ }
+
+ public Long getLastModelId() {
+ return lastModelId;
+ }
+
+ public void setLastModelId(Long lastModelId) {
+ this.lastModelId = lastModelId;
+ }
+
+ public String getLastModelName() {
+ return lastModelName;
+ }
+
+ public void setLastModelName(String lastModelName) {
+ this.lastModelName = lastModelName;
+ }
+
+ public String getSn() {
+ return sn;
+ }
+
+ public void setSn(String sn) {
+ this.sn = sn;
+ }
+
+ public String getSnGroupDetail() {
+ return snGroupDetail;
+ }
+
+ public void setSnGroupDetail(String snGroupDetail) {
+ this.snGroupDetail = snGroupDetail;
+ }
+
+ public String getSongTypeTop2() {
+ return songTypeTop2;
+ }
+
+ public void setSongTypeTop2(String songTypeTop2) {
+ this.songTypeTop2 = songTypeTop2;
+ }
+
+ public String getUserNickName() {
+ return userNickName;
+ }
+
+ public void setUserNickName(String userNickName) {
+ this.userNickName = userNickName;
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "Result{" +
+ "info=" + info +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "UserInfoEntity{" +
+ "result=" + result +
+ '}';
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/CarStatusListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/CarStatusListener.java
new file mode 100644
index 0000000000..f147a94a7c
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/CarStatusListener.java
@@ -0,0 +1,23 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.map.location.MogoLocation;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/13 11:02 AM
+ * desc : 车辆速度状态回调
+ *
+ * version: 1.0
+ */
+public interface CarStatusListener {
+ /**
+ * 当车辆从 行驶状态 进入 的时候回调
+ */
+ void onCarDriving2Stop(MogoLocation location);
+
+ /**
+ * 当车辆从 停车状态 进入 行驶状态 的时候回调
+ */
+ void onCarStop2Driving(MogoLocation location);
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XLocationListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XLocationListener.java
new file mode 100644
index 0000000000..b0b18824c8
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XLocationListener.java
@@ -0,0 +1,296 @@
+package com.mogo.module.v2x.listener;
+
+import android.content.Context;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.IMogoLocationListener;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.map.overlay.IMogoPolyline;
+import com.mogo.map.search.geo.IMogoGeoSearchListener;
+import com.mogo.map.search.geo.MogoGeocodeResult;
+import com.mogo.map.search.geo.MogoRegeocodeResult;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerResponse;
+import com.mogo.module.service.Utils;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.alarm.V2XAlarmServer;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.scenario.impl.V2XScenarioManager;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.DrivingDirectionUtils;
+import com.mogo.module.v2x.utils.LocationUtils;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/9 2:31 PM
+ * desc : V2X中用到的位置监听。处理刷新频率,以及位置改变是否触发道路事件警报
+ * version: 1.0
+ */
+public class V2XLocationListener implements IMogoLocationListener, CarStatusListener {
+ private String TAG = "V2XLocationListener";
+
+ private MogoLocation mLastCarLocation;
+ // 记录历史行驶轨迹,用于车行驶方向计算,只保留两个数据
+ private MogoLocation[] historyPath = new MogoLocation[2];
+ // 触发刷新的距离
+ private final int minDistance = 200;
+
+ private static V2XLocationListener mV2XLocationListener;
+
+ private V2XLocationListener() {
+ }
+
+ public synchronized static V2XLocationListener getInstance() {
+ synchronized (V2XLocationListener.class) {
+ if (mV2XLocationListener == null) {
+ mV2XLocationListener = new V2XLocationListener();
+ }
+ }
+ return mV2XLocationListener;
+ }
+
+ @Override
+ public void onLocationChanged(MogoLocation location) {
+ try {
+ Logger.d(V2XConst.MODULE_NAME, "V2X预警--onLocationChanged: " + GsonUtil.jsonFromObject(location));
+
+ // 刷新角度
+ getCurrentCarAngle(location);
+
+ // 只有车速大于 5 的时候进行计算
+ if (location.getSpeed() >= 5) {
+ refreshCurrentCarState(location);
+ }
+
+ // 车速从10降为0 这里统一交到 计算中心服务 进行计算,相应的状态会通过回调的方式调用
+ V2XServiceManager.getV2XCalculateServer().addCarStatusListener(TAG, this);
+ V2XServiceManager.getV2XCalculateServer().addCarTrajectory(location);
+
+ // 下面是道路刷新逻辑
+ if (mLastCarLocation == null) {
+ V2XServiceManager.getV2XMarkerService().refreshMarkerData(location);
+ mLastCarLocation = location;
+ }
+ // 计算车辆距离指定气泡的距离
+ float calculateDistance = Utils.calculateLineDistance(
+ new MogoLatLng(location.getLatitude(), location.getLongitude()),
+ new MogoLatLng(mLastCarLocation.getLatitude(), mLastCarLocation.getLongitude())
+ );
+
+ // 行驶距离 > 200M 重新请求
+ if (calculateDistance > minDistance) {
+ // Logger.d(MODULE_NAME, "V2X预警--移动距离>100米,重新刷新道路事件");
+ V2XServiceManager.getV2XMarkerService().refreshMarkerData(location);
+ mLastCarLocation = location;
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @param location 刷新当前车辆状态
+ */
+ private void refreshCurrentCarState(MogoLocation location) {
+ // 如果有道路事件正在预警的时候这里实时进行更新绘制
+ IMogoPolyline mMogoPolyline = V2XServiceManager.getMoGoV2XPolylineManager().getMogoPolyline();
+ if (mMogoPolyline != null && (V2XServiceManager.getMoGoV2XStatusManager().isRoadEventPOIShow()
+ || V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpPOIShow())
+ && V2XServiceManager.getV2XStatusManager().getTargetMoGoLatLng() != null) {
+ mMogoPolyline.setPoints(Arrays.asList(new MogoLatLng(location.getLatitude(), location.getLongitude()),
+ V2XServiceManager.getV2XStatusManager().getTargetMoGoLatLng()));
+
+ float zoomLevel = V2XServiceManager.getMapUIController().getZoomLevel();
+ //Logger.d(V2XConst.MODULE_NAME, "当前地图的缩放比例为:" + zoomLevel);
+ if (zoomLevel <= 17 && !V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow()) {
+ // 缩放地图
+ Context context = V2XServiceManager.getContext();
+ MarkerUtils.zoomMap(V2XServiceManager.getV2XStatusManager().getTargetMoGoLatLng(), context);
+ }
+ }
+
+ // 疲劳驾驶检测
+ V2XAlarmServer.getFatigueDrivingShow(location, drivingShowEntity -> {
+ Logger.i(V2XConst.MODULE_NAME, "疲劳驾驶POI查询结果为: " + GsonUtil.jsonFromObject(drivingShowEntity));
+
+ String style = V2XServiceManager.getMoGoStatusManager().isMainPageOnResume() ? "1" : "2";
+ trackWithType(V2XPoiTypeEnum.ALERT_FATIGUE_DRIVING, drivingShowEntity.getLon(), drivingShowEntity.getLat(), style);
+
+ V2XMessageEntity v2XMessageEntity = new V2XMessageEntity<>();
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_FATIGUE_DRIVING);
+ v2XMessageEntity.setContent(drivingShowEntity);
+ v2XMessageEntity.setShowState(drivingShowEntity.isShowWindow());
+ // 广播给ADAS Launcher
+ ADASUtils.broadcastToADAS(V2XServiceManager.getContext(), drivingShowEntity);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ });
+
+ // 巡航处理
+ V2XRoadEventEntity v2XRoadEventEntity =
+ V2XAlarmServer.getDriveFrontAlarmEvent(
+ V2XServiceManager.getMoGoV2XMarkerManager().getV2XRoadEventEntityList(),
+ V2XServiceManager.getV2XStatusManager().getLocation());
+ // 距离是否大于10米 && 消息是否不为空
+ if (v2XRoadEventEntity != null && v2XRoadEventEntity.getDistance() >= 5) {
+ Logger.w(MODULE_NAME,
+ //"\nV2X预警--当前导航状态:" + V2XServiceManager.getNavi().isNaviing() +
+ //"\nV2X预警--roadEventIsNullCount:" + roadEventIsNullCount +
+ "\nV2X预警--当前预警事件:" + v2XRoadEventEntity
+ );
+ // Logger.w(MODULE_NAME, "V2X预警--前方数据距离:" + v2XRoadEventEntity.getDistance());
+ // 触发展示操作
+ V2XMessageEntity v2XMessageEntity = new V2XMessageEntity<>();
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING);
+ v2XMessageEntity.setContent(v2XRoadEventEntity);
+ v2XMessageEntity.setShowState(true);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ }
+ }
+
+ public MogoLocation getLastCarLocation() {
+ try {
+ if (mLastCarLocation == null) {
+ MogoLatLng mogoLatLng = V2XServiceManager.getNavi().getCarLocation();
+ mLastCarLocation = new MogoLocation();
+ if (mogoLatLng != null) {
+ mLastCarLocation.setLongitude(mogoLatLng.getLon());
+ mLastCarLocation.setLatitude(mogoLatLng.getLat());
+ } else {
+ mLastCarLocation.setLongitude(0.0);
+ mLastCarLocation.setLatitude(0.0);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return mLastCarLocation;
+ }
+
+ /**
+ * 获取当前车辆的行驶方向 0<=Angle<=360
+ *
+ * @return 0<= Angle < = 3 6 0
+ */
+ private void getCurrentCarAngle(MogoLocation location) {
+ // 记录位置轨迹
+ if (historyPath[0] != null) {
+ historyPath[1] = historyPath[0];
+ }
+ historyPath[0] = location;
+
+ if (historyPath[1] != null && historyPath[0] != null) {
+ double carAngle =
+ DrivingDirectionUtils.getCarAngle(
+ historyPath[1].getLatitude(), historyPath[1].getLongitude(),
+ historyPath[0].getLatitude(), historyPath[0].getLongitude()
+ );
+
+ //Logger.d(MODULE_NAME,
+ // "\n车辆经纬度:" + Arrays.toString(historyPath) +
+ // "\n车辆角度:" + carAngle);
+ // 这里是真实的车辆角度
+ location.setBearing((float) carAngle);
+ } else {
+ //Logger.e(MODULE_NAME,
+ // "\n首次获取经纬度,默认车头朝北:" + Arrays.toString(historyPath));
+ location.setBearing(0.0f);
+ }
+ V2XServiceManager.getV2XStatusManager().setLocation(location);
+ }
+
+ /**
+ * 获取定位相关信息
+ */
+ private void getLocationInfo(MogoLocation location) {
+ // 定位当前位置是否是高速
+ LocationUtils.geoCodeSearch(location, new IMogoGeoSearchListener() {
+ @Override
+ public void onRegeocodeSearched(MogoRegeocodeResult regeocodeResult) {
+ Logger.i(MODULE_NAME, " 根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
+ location.setAddress(regeocodeResult.getRegeocodeAddress().getFormatAddress());
+ // 如果有 "高速"、"环线"、"快速路"等字眼的,视为封闭式道路,流程结束;
+ if (regeocodeResult.getRegeocodeAddress().getFormatAddress().contains("高速")
+ || regeocodeResult.getRegeocodeAddress().getFormatAddress().contains("环线")
+ || regeocodeResult.getRegeocodeAddress().getFormatAddress().contains("快速路")) {
+ } else {
+ searchIllegalParkData();
+ }
+ }
+
+ @Override
+ public void onGeocodeSearched(MogoGeocodeResult geocodeResult) {
+ }
+ });
+ }
+
+ /**
+ * 查询50米的违章停车数据
+ */
+ private void searchIllegalParkData() {
+ double lon = V2XServiceManager.getV2XStatusManager().getLocation().getLongitude();
+ double lat = V2XServiceManager.getV2XStatusManager().getLocation().getLatitude();
+
+ V2XServiceManager.getV2XRefreshModel()
+ .queryIllegalPark(new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(MarkerResponse result) {
+ Logger.i(MODULE_NAME, "搜索附近的违章停车点 成功:" + GsonUtil.jsonFromObject(result));
+ if (result != null) {
+ if (result.getResult().getExploreWay().size() > 0) {
+ V2XMessageEntity> entity = new V2XMessageEntity<>();
+ entity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ILLEGAL_PARK_WARNING);
+ entity.setContent(result.getResult().getExploreWay());
+ entity.setShowState(true);
+ V2XScenarioManager.getInstance().handlerMessage(entity);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+ Logger.e(MODULE_NAME, "搜索附近的违章停车点 失败:" + msg);
+ }
+ }, lon, lat);
+ }
+
+
+ @Override
+ public void onCarDriving2Stop(MogoLocation location) {
+ // 推迟30s主Launcher中的大而全的POI刷新时间
+ V2XServiceManager.getIMogoRefreshStrategyController().restartAutoRefreshAtTime(30000);
+ getLocationInfo(location);
+ }
+
+ @Override
+ public void onCarStop2Driving(MogoLocation location) {
+
+ }
+
+ //埋点
+ private static void trackWithType(String type, double lon, double lat, String style) {
+ Map properties = new HashMap<>();
+ properties.put("type", type);
+ properties.put("lng", lon);
+ properties.put("lat", lat);
+ properties.put("style", style);
+ V2XServiceManager.getMogoAnalytics().track(V2XConst.V2X_ROAD_SHOW, properties);
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMarkerClickListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMarkerClickListener.java
new file mode 100644
index 0000000000..cb79510fc4
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMarkerClickListener.java
@@ -0,0 +1,129 @@
+package com.mogo.module.v2x.listener;
+
+import android.text.TextUtils;
+
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.IMogoMarkerClickListener;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerOnlineCar;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.service.ServiceConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.utils.ChartingUtil;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/7 7:13 PM
+ * desc :
+ * version: 1.0
+ */
+public class V2XMarkerClickListener implements IMogoMarkerClickListener {
+
+ private static V2XMarkerClickListener markerClickListener;
+
+ // 最后一次选中的气泡
+ private IMogoMarker mLastCheckMarker;
+
+ private V2XMarkerClickListener() {
+ }
+
+ public synchronized static V2XMarkerClickListener getInstance() {
+ synchronized (V2XMarkerClickListener.class) {
+ if (markerClickListener == null) {
+ markerClickListener = new V2XMarkerClickListener();
+ }
+ }
+ return markerClickListener;
+ }
+
+ @Override
+ public boolean onMarkerClicked(IMogoMarker marker) {
+ try {
+ if (mLastCheckMarker != null) {
+ // 判断点击的是否是同一个
+ if (marker.equals(mLastCheckMarker)) {
+ Logger.d(MODULE_NAME, "onMarkerClicked 与上一次点击的Marker一样,不做处理:" + marker);
+ // 判断是在线车辆的时候处理打电话场景
+ try {
+ Object object = marker.getObject();
+ if (object != null) {
+ // 修改数据
+ MarkerShowEntity showEntity = (MarkerShowEntity) object;
+ if (showEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_USER_DATA)) {
+ Object bindObj = showEntity.getBindObj();
+ if (bindObj instanceof MarkerOnlineCar) {
+ MarkerLocation location = new MarkerLocation();
+ location.setLon(marker.getPosition().getLon());
+ location.setLat(marker.getPosition().getLat());
+ ChartingUtil.callChatting(
+ ((MarkerOnlineCar) bindObj).getUserInfo(),
+ location
+ );
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+ // 关闭上次的气泡
+ V2XServiceManager.getMoGoV2XMarkerManager().closeMarker(V2XServiceManager.getContext(), mLastCheckMarker);
+ }
+ // 将当前的Marker设置为选中
+ mLastCheckMarker = V2XServiceManager.getMoGoV2XMarkerManager().openMarker(V2XServiceManager.getContext(), marker);
+
+ // marker点击展示上半部分的浮窗,只加了道路事件
+ Object nov = marker.getObject();
+ Logger.d(MODULE_NAME, "marker点击====" + nov);
+ if (nov != null) {
+ MarkerShowEntity showEntity = (MarkerShowEntity) nov;
+ if (showEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_NOVELTY)) {
+ Object bindObj = showEntity.getBindObj();
+ if (bindObj instanceof MarkerExploreWay) {
+ MarkerExploreWay noveltyInfo = (MarkerExploreWay) bindObj;
+ Logger.d(MODULE_NAME, "新鲜事marker点击===" + bindObj);
+ V2XRoadEventEntity v2XRoadEventEntity = new V2XRoadEventEntity();
+ v2XRoadEventEntity.setLocation(noveltyInfo.getLocation());
+ v2XRoadEventEntity.setPoiType(noveltyInfo.getPoiType());
+ v2XRoadEventEntity.setNoveltyInfo(noveltyInfo);
+ v2XRoadEventEntity.setExpireTime(20000);
+ v2XRoadEventEntity.setDistance(1000);
+ //V2XServiceManager.getMoGoV2XScenarioManager().showRoadEventWindow(v2XRoadEventEntity, false);
+ return true;
+ }
+ } else if (showEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_ROAD_CONDITION)) {
+ Object bindObj = showEntity.getBindObj();
+ if (bindObj instanceof MarkerExploreWay) {
+ MarkerExploreWay markerExploreWay = (MarkerExploreWay) bindObj;
+ if (markerExploreWay.getItems().size() > 0
+ && !TextUtils.isEmpty(markerExploreWay.getItems().get(0).getUrl())) {
+ Logger.d(MODULE_NAME, "MarkerExploreWay点击===" + bindObj);
+ // 记录道路事件
+ V2XRoadEventEntity v2XRoadEventEntity = new V2XRoadEventEntity();
+ v2XRoadEventEntity.setLocation(markerExploreWay.getLocation());
+ // 探路目前只有上报拥堵
+ v2XRoadEventEntity.setPoiType(V2XPoiTypeEnum.FOURS_BLOCK_UP);
+
+ v2XRoadEventEntity.setDistance(1000);
+ v2XRoadEventEntity.setNoveltyInfo(markerExploreWay);
+ v2XRoadEventEntity.setExpireTime(20000);
+ //V2XServiceManager.getMoGoV2XScenarioManager().showRoadEventWindow(v2XRoadEventEntity, false);
+ return true;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401003.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401003.java
new file mode 100644
index 0000000000..3b179e600f
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401003.java
@@ -0,0 +1,123 @@
+package com.mogo.module.v2x.listener;
+
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.scenario.impl.V2XScenarioManager;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc :
+ * ADAS & V2X 场景触发push
+ * TODO 前瞻需求,这里是后台下发 http://h5service.zhidaohulian.com/v2x_remoteControl/#/
+ * version: 1.0
+ */
+public class V2XMessageListener_401003 implements IMogoOnMessageListener {
+
+ @Override
+ public Class target() {
+ return V2XPushMessageEntity.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XPushMessageEntity message) {
+ Logger.i(MODULE_NAME, "V2XMessageListener_401003:" + GsonUtil.jsonFromObject(message));
+ V2XUtils.runOnUiThread(() -> {
+ try {
+ handlerV2XAlarm(message);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * 处理V2X场景
+ *
+ * @param alarmMessage V2X消息
+ */
+ private void handlerV2XAlarm(V2XPushMessageEntity alarmMessage) {
+ // 绘制道路事件
+ //Logger.w(MODULE_NAME, "处理V2X场景SceneId==" + alarmMessage.getSceneId());
+
+ // 修改地图比例尺
+ if (alarmMessage.getZoomScale() > 0) {
+ V2XServiceManager.getMoGoStatusManager().setUserInteractionStatus(MODULE_NAME, true, true);
+ MarkerUtils.resetMapZoom(alarmMessage.getZoomScale());
+ }
+
+ V2XMessageEntity v2XMessageEntity = new V2XMessageEntity<>();
+ switch (alarmMessage.getSceneId()) {
+ case "100000"://前车碰撞预警
+ case "100001"://车道偏离预警
+ //V2XWindowManager.removeAllV2XView();
+ break;
+
+ // 下面的场景,地图缩小,显示30秒直播小视频,视频播放结束恢复地图比例尺
+ case "100002"://盲区换道警告
+ case "100003"://盲区行人碰撞预警
+ case "100009"://危险路段(施工)告警
+ case "100010"://拥堵告警
+ case "100004"://逆向超车碰撞预警
+ case "100011"://失控车辆告警
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_LIVE_CAR_WARNING);
+ v2XMessageEntity.setContent(alarmMessage);
+ v2XMessageEntity.setShowState(true);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ break;
+ // 下面的场景禁行动画效果展示
+ case "100005"://前车紧急制动告警
+ case "100006"://十字路口碰撞预警
+ case "100007"://岔路口碰撞预警
+ case "100008"://禁行车道预警
+ case "100012"://应急车辆优先通行
+ case "100013"://闯红灯预警
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ANIMATION_WARNING);
+ v2XMessageEntity.setContent(alarmMessage);
+ v2XMessageEntity.setShowState(true);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ break;
+ case "100015"://取快递
+ case "100016"://顺风车
+ case "100017"://政府公告
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_WINDOW_WARNING);
+ v2XMessageEntity.setContent(alarmMessage);
+ v2XMessageEntity.setShowState(true);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ break;
+ case "100014"://行人点赞
+ showTip(alarmMessage.getTts());
+ ADASUtils.broadcastToADAS_TTS(V2XServiceManager.getContext(), alarmMessage);
+ break;
+ default:
+ ADASUtils.broadcastToADAS_TTS(V2XServiceManager.getContext(), alarmMessage);
+ break;
+ }
+ }
+
+ private void showTip(String msg) {
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ View toastView = LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view, null);
+ TextView msgView = toastView.findViewById(R.id.tvFeedbackContent);
+ msgView.setText(msg);
+ ToastUtils.showCustomShort(toastView);
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401005.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401005.java
new file mode 100644
index 0000000000..304be7162f
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401005.java
@@ -0,0 +1,94 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.v2x.scenario.impl.V2XScenarioManager;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc : 特殊车辆推送绘制
+ * version: 1.0
+ */
+public class V2XMessageListener_401005 implements IMogoOnMessageListener {
+ @Override
+ public Class target() {
+ return V2XSpecialCarRes.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XSpecialCarRes message) {
+ Logger.i(MODULE_NAME, "V2XMessageListener_401005:" + GsonUtil.jsonFromObject(message));
+ if (!V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow()) {
+ V2XUtils.runOnBackgroundThread(() -> {
+ try {
+ MarkerUtils.handlerV2XSpecialVehicleMarker(
+ message,
+ V2XServiceManager.getContext(),
+ V2XMarkerClickListener.getInstance());
+
+ //获取经纬度信息
+ //根据sn获取用户信息
+ //V2XWindowManager展示
+ handleSeekHelp(message);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+ }
+
+
+ /**
+ * 处理故障求助
+ */
+ private void handleSeekHelp(V2XSpecialCarRes message) {
+ if (message == null) {
+ return;
+ }
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_MARKER_SPECIAL_CAR);
+ List coordinates = message.getCoordinates();
+ List entityList = new ArrayList<>();
+ // 移除上一次的数据
+ //Context context = V2XServiceManager.getContext();
+
+ for (V2XMarkerEntity coordinate : coordinates) {
+ //故障车机
+ if (coordinate.getTargetId() == V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING) {
+ //V2XMarkerEntity.UserInfoBean userInfoBean = coordinate.getUserInfo();
+ //if (userInfoBean != null) {
+ entityList.add(coordinate);
+ //}
+ //绘制
+ //V2XServiceManager
+ // .getMoGoV2XMarkerManager()
+ // .drawableSpecialCarPOI(context, coordinate, V2XMarkerClickListener.getInstance());
+ }
+ }
+ if (!entityList.isEmpty()) {
+ //V2XUtils.runOnUiThread(() -> V2XServiceManager.getMoGoV2XScenarioManager().showOtherSeekHelpWindow(entityList));
+ V2XUtils.runOnUiThread(() -> {
+ V2XMessageEntity> v2XMessageEntity = new V2XMessageEntity<>();
+ v2XMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_SEEK_WARNING);
+ v2XMessageEntity.setContent(entityList);
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ });
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401006.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401006.java
new file mode 100644
index 0000000000..def6c3032b
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401006.java
@@ -0,0 +1,30 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.module.v2x.entity.net.V2XAlarmEventRes;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc :
+ * 3.2.1、前方静止or慢速车辆报警
+ * 3.2.2、道路危险状况告警 / 前方拥堵告警
+ * version: 1.0
+ */
+@Deprecated
+public class V2XMessageListener_401006 implements IMogoOnMessageListener {
+
+ @Override
+ public Class target() {
+ return V2XAlarmEventRes.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XAlarmEventRes message) {
+ Logger.i(MODULE_NAME, "iMogoOnMessageListener_401006:" + message);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401007.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401007.java
new file mode 100644
index 0000000000..fe6d581741
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401007.java
@@ -0,0 +1,48 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.module.service.MarkerServiceHandler;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XAlarmEventRes;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc : 限行通知
+ * version: 1.0
+ */
+public class V2XMessageListener_401007 implements IMogoOnMessageListener {
+ @Override
+ public Class target() {
+ return V2XAlarmEventRes.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XAlarmEventRes message) {
+ Logger.i(MODULE_NAME, "V2XMessageListener_401007:" + message);
+ try {
+ if (message != null) {
+
+ // 发送广播
+ V2XAlarmEventRes.AlarmInfo alarmInfo = message.getResult().getAlarmInfo();
+ ADASUtils.broadcastToADAS_TTS(V2XServiceManager.getContext(), alarmInfo);
+
+ // 统计代码
+ final Map properties = new HashMap<>();
+ properties.put("warning_id", V2XPoiTypeEnum.ALERT_TRAFFIC_CONTROL);
+ MarkerServiceHandler.getMogoAnalytics().track("v2x_warning", properties);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401009.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401009.java
new file mode 100644
index 0000000000..2b081aba24
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401009.java
@@ -0,0 +1,50 @@
+package com.mogo.module.v2x.listener;
+
+import android.view.Gravity;
+import android.view.LayoutInflater;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.entity.net.V2XGiveLike;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc :
+ * * 2.0.2
+ * * http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=35786774
+ * * 注册点赞通信接收
+ * version: 1.0
+ */
+public class V2XMessageListener_401009 implements IMogoOnMessageListener {
+ @Override
+ public Class target() {
+ return V2XGiveLike.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XGiveLike message) {
+ Logger.i(MODULE_NAME, "V2XMessageListener_401009:" + message);
+ try {
+ V2XPushMessageEntity v2XAlarmMessage = new V2XPushMessageEntity();
+ v2XAlarmMessage.setTts(message.getResult());
+ v2XAlarmMessage.setAlarmContent(message.getResult());
+ v2XAlarmMessage.setExpireTime(20000);
+ v2XAlarmMessage.setSceneId("000000");
+ ADASUtils.broadcastToADAS_TTS(V2XServiceManager.getContext(), v2XAlarmMessage);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ ToastUtils.showCustomLong(LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view_feedback_img_text, null));
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401010.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401010.java
new file mode 100644
index 0000000000..16883842ff
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401010.java
@@ -0,0 +1,47 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.module.v2x.entity.net.V2XAlarmEventRes;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc :
+ * * 2.0.3
+ * * http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=35788659
+ * * TODO 停车场、加油站推送心跳,这里是前瞻的功能,目前仅在分体机使用,
+ * version: 1.0
+ */
+@Deprecated
+public class V2XMessageListener_401010 implements IMogoOnMessageListener {
+
+ @Override
+ public Class target() {
+ return V2XAlarmEventRes.class;
+ }
+
+ @Override
+ public void onMsgReceived(V2XAlarmEventRes message) {
+ Logger.i(MODULE_NAME, "V2XMessageListener_401010:" + message);
+ try {
+ if (message != null
+ && message.getResult() != null) {
+
+ // 处理报警事件
+ handlerAlarmInfo();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 处理道路事件提醒
+ */
+ private void handlerAlarmInfo() {
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401011.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401011.java
new file mode 100644
index 0000000000..55afafbd77
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XMessageListener_401011.java
@@ -0,0 +1,43 @@
+package com.mogo.module.v2x.listener;
+
+import com.mogo.module.common.entity.MarkerCardResult;
+import com.mogo.module.common.entity.MarkerResponse;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.connection.IMogoOnMessageListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/1 10:23 AM
+ * desc : 道路事件,实际就是大而全的数据进行的过滤
+ * version: 1.0
+ */
+public class V2XMessageListener_401011 implements IMogoOnMessageListener {
+
+ @Override
+ public Class target() {
+ return MarkerResponse.class;
+ }
+
+ @Override
+ public void onMsgReceived(MarkerResponse response) {
+ Logger.d(MODULE_NAME, "V2XMessageListener_401011==V2X地图气泡数据刷新:\n" + GsonUtil.jsonFromObject(response));
+ if (!V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow()) {
+ V2XUtils.runOnBackgroundThread(() -> {
+ // 解析不同的Marker类型,然后对应的进行绘制
+ if (response != null && response.getResult() != null) {
+ MarkerCardResult markerCardResult = response.getResult();
+ // 解析存储道路事件
+ //V2XServiceManager.getMoGoV2XMarkerManager().drawableV2XMarker(markerCardResult);
+ V2XServiceManager.getMoGoV2XMarkerManager().analysisV2XRoadEvent(markerCardResult);
+ }
+ });
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XWindowStatusListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XWindowStatusListener.java
new file mode 100644
index 0000000000..41d26f5d34
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/listener/V2XWindowStatusListener.java
@@ -0,0 +1,14 @@
+package com.mogo.module.v2x.listener;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/15 10:20 AM
+ * desc : V2X 窗体状态回调
+ * version: 1.0
+ */
+public interface V2XWindowStatusListener {
+ void onViewShow();
+
+ void onViewClose();
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XMarkerManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XMarkerManager.java
new file mode 100644
index 0000000000..f1e987d46d
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XMarkerManager.java
@@ -0,0 +1,163 @@
+package com.mogo.module.v2x.manager;
+
+import android.content.Context;
+
+import com.alibaba.android.arouter.facade.template.IProvider;
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.IMogoMarkerClickListener;
+import com.mogo.module.common.entity.MarkerCardResult;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerNoveltyInfo;
+import com.mogo.module.common.entity.MarkerOnlineCar;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 8:15 PM
+ * desc : V2X 涉及到的地图 POI 点的绘制
+ * version: 1.0
+ */
+public interface IMoGoV2XMarkerManager extends IProvider {
+
+ /**
+ * 重新绘制最后一次的POI点
+ */
+ void drawableLastAllPOI();
+
+ /**
+ * 获取所有的道路事件点,探路事件,返回结果是按照距离当前车辆从近到远排列好的
+ *
+ * @return 按从近到远排列好的道路事件
+ */
+ CopyOnWriteArrayList getV2XRoadEventEntityList();
+
+ /**
+ * 从探路数据和新鲜事儿的路况信息中解析出道路事件信息
+ */
+ void analysisV2XRoadEvent(MarkerCardResult markerCardResult);
+
+ /**
+ * 绘制V2X 地图点事件
+ *
+ * @param markerCardResult 大而全中过滤出来的点事件
+ */
+ void drawableV2XMarker(MarkerCardResult markerCardResult);
+
+ /**
+ * 绘制 在线车辆 POI
+ *
+ * @param markerOnlineCars
+ * @param clickListener
+ */
+ void drawableOnlineCarPOI(List markerOnlineCars, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 在线车辆 POI
+ */
+ void clearOnlineCarPOI();
+
+ /**
+ * 绘制 特殊车辆
+ *
+ * @param context
+ * @param v2XMarkerEntity
+ * @param clickListener
+ */
+ void drawableSpecialCarPOI(Context context, V2XMarkerEntity v2XMarkerEntity, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 特殊车辆 POI
+ */
+ void clearSpecialCarPOI();
+
+ /**
+ * 绘制可以直播的在线车辆
+ *
+ * @param markerOnlineCars
+ * @param clickListener
+ */
+ void drawableLiveCarPOI(List markerOnlineCars, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 可以直播的在线车辆 POI
+ */
+ void clearLiveCarPOI();
+
+ /**
+ * 绘制 探路
+ *
+ * @param exploreWayList
+ * @param clickListener
+ */
+ void drawableExplorePOI(List exploreWayList, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 探路 POI
+ */
+ void clearExplorePOI();
+
+ /**
+ * 绘制 新鲜事儿
+ *
+ * @param noveltyInfoList
+ * @param clickListener
+ */
+ void drawableNoveltyPOI(List noveltyInfoList, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 新鲜事儿 POI
+ */
+ void clearNoveltyPOI();
+
+ /**
+ * 绘制Marker,上面调用的都是这个方法
+ *
+ * @param context
+ * @param markerShowEntity
+ * @param clickListener
+ */
+ void drawableMarker(Context context, MarkerShowEntity markerShowEntity, IMogoMarkerClickListener clickListener);
+
+
+ /**
+ * 展开气泡
+ *
+ * @param context
+ * @param currentMarker
+ */
+ IMogoMarker openMarker(Context context, IMogoMarker currentMarker);
+
+ /**
+ * 关闭气泡
+ *
+ * @param context
+ * @param currentMarker
+ */
+ void closeMarker(Context context, IMogoMarker currentMarker);
+
+ /**
+ * 绘制正在预警的道路事件的POI点
+ *
+ * @param context
+ * @param roadEventEntity
+ */
+ void drawableAlarmPOI(Context context, V2XRoadEventEntity roadEventEntity, IMogoMarkerClickListener clickListener);
+
+ /**
+ * 清除 道路事件 POI
+ */
+ void clearAlarmPOI();
+
+ /**
+ * 清除 所有的 POI
+ */
+ void clearALLPOI();
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XPolylineManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XPolylineManager.java
new file mode 100644
index 0000000000..237dd6d0f3
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XPolylineManager.java
@@ -0,0 +1,31 @@
+package com.mogo.module.v2x.manager;
+
+import android.content.Context;
+
+import com.alibaba.android.arouter.facade.template.IProvider;
+import com.mogo.map.overlay.IMogoPolyline;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 9:49 PM
+ * desc : 当前车辆与道路事件的连接线
+ * version: 1.0
+ */
+public interface IMoGoV2XPolylineManager extends IProvider {
+ /**
+ * 绘制连接线,目标车,与当前车辆间连线
+ *
+ * @param context
+ * @param roadEventEntity
+ */
+ void drawablePolyline(Context context, V2XRoadEventEntity roadEventEntity);
+
+ /**
+ * 移除连接线
+ */
+ void clearLine();
+
+ IMogoPolyline getMogoPolyline();
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusChangedListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusChangedListener.java
new file mode 100644
index 0000000000..b200d52777
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusChangedListener.java
@@ -0,0 +1,19 @@
+package com.mogo.module.v2x.manager;
+
+import com.alibaba.android.arouter.facade.template.IProvider;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 7:44 PM
+ * desc : 状态控制器监听
+ * version: 1.0
+ */
+public interface IMoGoV2XStatusChangedListener extends IProvider {
+
+ /**
+ * @param descriptor 状态类型
+ * @param isTrue true - v2x ui show
+ */
+ void onStatusChanged(V2XStatusDescriptor descriptor, boolean isTrue);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusManager.java
new file mode 100644
index 0000000000..ca47257765
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/IMoGoV2XStatusManager.java
@@ -0,0 +1,188 @@
+package com.mogo.module.v2x.manager;
+
+import com.alibaba.android.arouter.facade.template.IProvider;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 7:20 PM
+ * desc : V2X 状态管理
+ * version: 1.0
+ */
+public interface IMoGoV2XStatusManager extends IProvider {
+ /**
+ * 地图区域 V2X道路预警POI 是否在展示
+ */
+ boolean isRoadEventPOIShow();
+
+ /**
+ * 按钮区 V2X道路预警 是否在展示
+ */
+ boolean isRoadEventButtonShow();
+
+ /**
+ * 头部 V2X道路预警 UI 是否在展示
+ */
+ boolean isRoadEventWindowShow();
+
+ /**
+ * 头部 V2X的道路直播 UI 是否在展示
+ */
+ boolean isRoadLiveCarWindowShow();
+
+ /**
+ * 头部 他人车辆故障求助 UI 是否在展示
+ */
+ boolean isOtherSeekHelpWindowShow();
+
+ /**
+ * 地图区域 自身的道路求助按钮 是否在展示
+ */
+ boolean isMeSeekHelpButtonShow();
+
+ /**
+ * 地图区域 他人车辆故障求助POI 是否在展示
+ */
+ boolean isOtherSeekHelpPOIShow();
+
+ /**
+ * 前瞻需求
+ * 右侧2/3 V2X 场景动画 UI 是否在展示
+ */
+ boolean isV2XAnimationShow();
+
+ /**
+ * 前瞻需求
+ * 右侧2/3 左下角 模拟直播车机 UI 是否在展示
+ */
+ boolean isLeftLiveVideoShow();
+
+ /**
+ * 推送弹窗的状态
+ */
+ boolean isPushWindowShow();
+
+ /**
+ * 推送的 POI 状态
+ */
+ boolean isPushPOIShow();
+
+ /**
+ * 疲劳驾驶 状态
+ */
+ boolean isFatigueDrivingWindowShow();
+
+ /**
+ * 设置 V2X道路预警POI 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setRoadEventPOIShow(String tag, boolean show);
+
+ /**
+ * 设置 V2X道路预警 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setRoadEventButtonShow(String tag, boolean show);
+
+ /**
+ * 设置 右侧2/3 头部 V2X道路预警 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setRoadEventWindowShow(String tag, boolean show);
+
+ /**
+ * 设置 右侧2/3 头部 V2X的道路直播 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setRoadLiveCarWindowShow(String tag, boolean show);
+
+ /**
+ * 设置 他人车辆故障求助 UI 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setOtherSeekHelpWindowShow(String tag, boolean show);
+
+ /**
+ * 地图区域 自身的道路求助按钮 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setMeSeekHelpButtonShow(String tag, boolean show);
+
+ /**
+ * 地图区域 他人车辆故障求助POI 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setOtherSeekHelpPOIShow(String tag, boolean show);
+
+ /**
+ * 设置 右侧2/3 全屏 V2X 场景动画 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setV2XAnimationWindowShow(String tag, boolean show);
+
+ /**
+ * 设置 模拟直播车机 UI 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setLiveCarWindowShow(String tag, boolean show);
+
+ /**
+ * 推送弹窗的状态
+ *
+ * @param tag
+ * @param show
+ */
+ void setPushWindowShow(String tag, boolean show);
+
+ /**
+ * 地图区域 推送的 POI 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setPushPOIShow(String tag, boolean show);
+
+ /**
+ * 地图区域 疲劳驾驶 是否在展示
+ *
+ * @param tag
+ * @param show
+ */
+ void setFatigueDrivingWindowShow(String tag, boolean show);
+
+ /**
+ * 注册监听
+ *
+ * @param tag 业务类型
+ * @param descriptor 监听类型
+ * @param listener 监听回调
+ */
+ void registerStatusChangedListener(String tag, V2XStatusDescriptor descriptor, IMoGoV2XStatusChangedListener listener);
+
+ /**
+ * 注销
+ *
+ * @param tag 业务类型
+ * @param descriptor 注销类型
+ * @param listener 注销回调
+ */
+ void unregisterStatusChangedListener(String tag, V2XStatusDescriptor descriptor, IMoGoV2XStatusChangedListener listener);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/V2XStatusDescriptor.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/V2XStatusDescriptor.java
new file mode 100644
index 0000000000..0cf7973e0a
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/V2XStatusDescriptor.java
@@ -0,0 +1,70 @@
+package com.mogo.module.v2x.manager;
+
+/**
+ * @author congtaowang
+ * @since 2020-01-04
+ *
+ * 状态描述
+ */
+public enum V2XStatusDescriptor {
+
+ /**
+ * 地图 V2X道路预警POI
+ */
+ RoadEventPOI_UI,
+
+ /**
+ * 按钮 V2X道路预警
+ */
+ RoadEventButton_UI,
+
+ /**
+ * 头部 V2X道路预警 UI
+ */
+ RoadEventWindow_UI,
+
+ /**
+ * 头部 V2X的道路直播 UI
+ */
+ RoadLiveCarWindow_UI,
+
+ /**
+ * 地图 他人车辆故障求助POI
+ */
+ OtherSeekHelpPOI_UI,
+
+ /**
+ * 头部 他人车辆故障求助 UI 是否在展示
+ */
+ OtherSeekHelpWindow_UI,
+
+ /**
+ * 头部 自身的道路求助按钮 UI 是否在展示
+ */
+ MeSeekHelpButton_UI,
+
+ /**
+ * 右侧2/3 V2X 场景动画 UI 是否在展示
+ */
+ V2XAnimationWindow_UI,
+
+ /**
+ * 右侧2/3 左下角 模拟直播车机 UI 是否在展示
+ */
+ LiveCarWindow_UI,
+
+ /**
+ * 推送的POI
+ */
+ PushWindowPOI_UI,
+
+ /**
+ * 推送的弹窗
+ */
+ PushWindow_UI,
+
+ /**
+ * 疲劳驾驶弹窗
+ */
+ FatigueDrivingWindow_UI,
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XMarkerManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XMarkerManager.java
new file mode 100644
index 0000000000..72aac3e4d9
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XMarkerManager.java
@@ -0,0 +1,572 @@
+package com.mogo.module.v2x.manager.impl;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.IMogoMarkerClickListener;
+import com.mogo.map.marker.MogoMarkerOptions;
+import com.mogo.map.uicontroller.EnumMapUI;
+import com.mogo.module.common.entity.MarkerCardResult;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerNoveltyInfo;
+import com.mogo.module.common.entity.MarkerOnlineCar;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.service.ServiceConst;
+import com.mogo.module.service.Utils;
+import com.mogo.module.service.marker.IMarkerView;
+import com.mogo.module.service.marker.MapMarkerAdapter;
+import com.mogo.module.service.utils.ViewUtils;
+import com.mogo.module.v2x.MoGoV2XServicePaths;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.listener.V2XMarkerClickListener;
+import com.mogo.module.v2x.manager.IMoGoV2XMarkerManager;
+import com.mogo.module.v2x.marker.V2XMarkerAdapter;
+import com.mogo.module.v2x.utils.EventTypeUtils;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.utils.logger.Logger;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+import static com.mogo.module.v2x.V2XConst.V2X_EVENT_ALARM_POI;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 9:57 PM
+ * desc : V2X 涉及到的地图 POI 点的绘制
+ * version: 1.0
+ */
+@Route(path = MoGoV2XServicePaths.PATH_V2X_MARKER_MANAGER)
+public class MoGoV2XMarkerManager implements IMoGoV2XMarkerManager {
+ private static final String TAG = "MoGoV2XMarkerManager";
+
+ // 记录所有的:新鲜事儿的道路事件点、探路事件
+ private static CopyOnWriteArraySet mV2XRoadEventEntityArrayList = new CopyOnWriteArraySet<>();
+ // 上次的道路事件的预警Marker
+ private static IMogoMarker mAlarmInfoMarker;
+
+ @Override
+ public void drawableLastAllPOI() {
+ //Logger.w(MODULE_NAME, "V2X---绘制上一次的POI,回调给Launcher底层逻辑让其进行绘制");
+ // 清除连接线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ clearAlarmPOI();
+ clearSpecialCarPOI();
+ // 开启主Launcher刷新
+ V2XServiceManager.getIMogoRefreshStrategyController().restartAutoRefreshAtTime(500);
+ }
+
+ @Override
+ public CopyOnWriteArrayList getV2XRoadEventEntityList() {
+ CopyOnWriteArrayList roadEventEntities = new CopyOnWriteArrayList<>();
+ // 当前车辆数据
+ MogoLocation currentLocation = V2XServiceManager.getV2XStatusManager().getLocation();
+
+ if (currentLocation != null) {
+ // 重新计算距离
+ for (V2XRoadEventEntity v2XRoadEventEntity : mV2XRoadEventEntityArrayList) {
+ // 事件位置
+ MarkerLocation location = v2XRoadEventEntity.getLocation();
+ if (location != null) {
+ float calculateDistance = Utils.calculateLineDistance(
+ new MogoLatLng(location.getLat(), location.getLon()),
+ new MogoLatLng(currentLocation.getLatitude(), currentLocation.getLongitude())
+ );
+ v2XRoadEventEntity.setDistance(calculateDistance);
+ }
+ roadEventEntities.add(v2XRoadEventEntity);
+ }
+
+ // 按照与当前车辆距离排序
+ for (int i = 0; i < roadEventEntities.size(); i++) {
+ for (int j = i; j > 0; j--) {
+ if (roadEventEntities.get(j).getDistance() < roadEventEntities.get(j - 1).getDistance()) {
+ V2XRoadEventEntity v2XRoadEventEntity = roadEventEntities.get(j - 1);
+ roadEventEntities.set(j - 1, roadEventEntities.get(j));
+ roadEventEntities.set(j, v2XRoadEventEntity);
+ }
+ }
+ }
+ //输出日志查看结果
+// Log.w(TAG, "V2X===============================");
+// for (int i = 0; i < roadEventEntities.size(); i++) {
+// Log.w(TAG, "V2X===" +
+// "事件名称:" + roadEventEntities.get(i).getNoveltyInfo() +
+// "\t 事件距离:" + roadEventEntities.get(i).getDistance());
+// }
+ }
+
+ return roadEventEntities;
+ }
+
+ @Override
+ public void analysisV2XRoadEvent(MarkerCardResult markerCardResult) {
+ // 预警Window状态
+ boolean isShowEventWindow = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow();
+ // 预警按钮状态
+ boolean isShowEventButton = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventButtonShow();
+ // 道路求助的window
+ boolean isOtherSeekHelpWindowShow = V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpWindowShow();
+ try {
+ //当没有预警提示的时候重新绘制地图POI点
+ if (markerCardResult != null && !isShowEventWindow && !isShowEventButton && !isOtherSeekHelpWindowShow) {
+ // 清除上次的道路事件, 这里注意,道路事件的触发和这里是异步操作会触发异常
+ mV2XRoadEventEntityArrayList.clear();
+
+ // 获取探路以及新鲜事儿
+ List exploreWayList = markerCardResult.getExploreWay();
+
+ if (exploreWayList != null) {
+ for (MarkerExploreWay markerExploreWay : exploreWayList) {
+ // 因为目前探路卡片不支持直播,所以这里做了过滤 @李小鹏
+ if (!markerExploreWay.getCanLive()) {
+ if (EventTypeUtils.isRoadEvent(markerExploreWay.getPoiType())) {
+ MarkerLocation markerLocation = markerExploreWay.getLocation();
+ // 记录道路事件
+ V2XRoadEventEntity v2XRoadEventEntity = new V2XRoadEventEntity();
+ v2XRoadEventEntity.setLocation(markerLocation);
+ // 探路目前只有上报拥堵
+ v2XRoadEventEntity.setPoiType(markerExploreWay.getPoiType());
+
+ v2XRoadEventEntity.setNoveltyInfo(markerExploreWay);
+ v2XRoadEventEntity.setExpireTime(20000);
+ mV2XRoadEventEntityArrayList.add(v2XRoadEventEntity);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void drawableV2XMarker(MarkerCardResult markerCardResult) {
+ // 预警Window状态
+ boolean isShowEventWindow = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow();
+ // 预警按钮状态
+ boolean isShowEventButton = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventButtonShow();
+ // 道路求助的window
+ boolean isOtherSeekHelpWindowShow = V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpWindowShow();
+ try {
+ //当没有预警提示的时候重新绘制地图POI点
+ if (!isShowEventWindow && !isShowEventButton && !isOtherSeekHelpWindowShow) {
+ // 清除上次的道路事件,TODO 这里注意,道路事件的触发和这里是异步操作会触发异常
+ //mV2XRoadEventEntityArrayList.clear();
+ // 清除原来的大而全的新鲜事儿
+ try {
+ clearALLPOI();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // 清除连接线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ if (markerCardResult != null) {
+ // 绘制新的地图气泡
+ List onlineCarList = markerCardResult.getOnlineCar();
+ List exploreWayList = markerCardResult.getExploreWay();
+ List noveltyInfoList = markerCardResult.getNoveltyInfo();
+
+ drawableOnlineCarPOI(onlineCarList, V2XMarkerClickListener.getInstance());
+ drawableExplorePOI(exploreWayList, V2XMarkerClickListener.getInstance());
+ drawableNoveltyPOI(noveltyInfoList, V2XMarkerClickListener.getInstance());
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void drawableOnlineCarPOI(List markerOnlineCars, IMogoMarkerClickListener clickListener) {
+ try {
+ if (markerOnlineCars != null) {
+ for (MarkerOnlineCar markerOnlineCar : markerOnlineCars) {
+ MarkerLocation markerLocation = markerOnlineCar.getLocation();
+
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setBindObj(markerOnlineCar);
+ markerShowEntity.setMarkerLocation(markerLocation);
+ markerShowEntity.setMarkerType(markerOnlineCar.getType());
+ markerShowEntity.setTextContent(markerOnlineCar.getUserInfo().getSafeLabel());
+ markerShowEntity.setIconUrl(markerOnlineCar.getUserInfo().getUserHead());
+
+ drawableMarker(V2XServiceManager.getContext(), markerShowEntity, clickListener);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearOnlineCarPOI() {
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_CARD_TYPE_USER_DATA);
+ }
+
+ @Override
+ public void drawableSpecialCarPOI(Context context, V2XMarkerEntity v2XMarkerEntity, IMogoMarkerClickListener clickListener) {
+ try {
+ MarkerUtils.resetMapZoom(15);
+ V2XServiceManager.getMapUIController().changeMapMode(EnumMapUI.NorthUP_2D);
+ V2XServiceManager.getMoGoV2XStatusManager().setOtherSeekHelpPOIShow(TAG, true);
+
+ // 绘制特殊车辆
+ if (v2XMarkerEntity == null) {
+ return;
+ }
+ MarkerLocation markerLocation = new MarkerLocation();
+ markerLocation.setLon(v2XMarkerEntity.getLon());
+ markerLocation.setLat(v2XMarkerEntity.getLat());
+
+ // 进行数据转换,用于Marker展示
+ V2XRoadEventEntity roadEventEntity = new V2XRoadEventEntity();
+ roadEventEntity.setPoiType(v2XMarkerEntity.getTargetId() + "");
+ roadEventEntity.setLocation(markerLocation);
+ roadEventEntity.setBindObj(v2XMarkerEntity);
+
+ // 重置告警信息
+ V2XServiceManager.getV2XStatusManager().setAlarmInfo(roadEventEntity);
+
+ // 清除原来的大而全的新鲜事儿
+ clearALLPOI();
+ if (roadEventEntity.getLocation() != null) {
+ // 道路事件,或者水波纹扩散效果
+ MogoMarkerOptions optionsRipple = new MogoMarkerOptions()
+ .object(roadEventEntity)
+ .latitude(roadEventEntity.getLocation().getLat())
+ .longitude(roadEventEntity.getLocation().getLon());
+ optionsRipple.anchor(0.5f, 0.5f);
+
+ // 由于性能问题,D车机不使用事件扩散动画
+ optionsRipple.icon(V2XMarkerAdapter.getV2XRoadEventViewPng(context, roadEventEntity));
+ mAlarmInfoMarker = V2XServiceManager.getMarkerManager().addMarker(V2X_EVENT_ALARM_POI, optionsRipple);
+ // 当前Marker设置为最上面
+ mAlarmInfoMarker.setToTop();
+// if (clickListener != null) {
+// mAlarmInfoMarker.setOnMarkerClickListener(clickListener);
+// }
+ // 绘制连接线
+ V2XServiceManager.getMoGoV2XPolylineManager().drawablePolyline(context, roadEventEntity);
+ } else {
+ Logger.e(MODULE_NAME, "Location 必须进行初始化!!!!!");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearSpecialCarPOI() {
+ boolean isOtherSeekHelpPOIShow = V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpPOIShow();
+ if (isOtherSeekHelpPOIShow) {
+ V2XServiceManager.getMoGoV2XStatusManager().setOtherSeekHelpPOIShow(TAG, false);
+ // 重置告警信息
+ V2XServiceManager.getV2XStatusManager().setAlarmInfo(null);
+ if (mAlarmInfoMarker != null) {
+ mAlarmInfoMarker.remove();
+ }
+ }
+ }
+
+ @Override
+ public void drawableLiveCarPOI(List markerOnlineCars, IMogoMarkerClickListener clickListener) {
+ try {
+ Logger.w(MODULE_NAME, "V2X===事件周边的直播车机:" + markerOnlineCars);
+ if (markerOnlineCars != null) {
+ for (MarkerOnlineCar markerOnlineCar : markerOnlineCars) {
+ // 设置车类型
+ markerOnlineCar.getUserInfo().setSafeLabelType(4);
+ markerOnlineCar.getCarInfo().setVehicleType(0);
+
+ MarkerLocation markerLocation = markerOnlineCar.getLocation();
+
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setBindObj(markerOnlineCar);
+ markerShowEntity.setMarkerLocation(markerLocation);
+ markerShowEntity.setMarkerType(V2XConst.V2X_MARKER_LIVE_CAR);
+ markerShowEntity.setTextContent(markerOnlineCar.getUserInfo().getSafeLabel());
+ markerShowEntity.setIconUrl(markerOnlineCar.getUserInfo().getUserHead());
+
+ drawableMarker(
+ V2XServiceManager.getContext(),
+ markerShowEntity,
+ clickListener);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearLiveCarPOI() {
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_MARKER_LIVE_CAR);
+ }
+
+ @Override
+ public void drawableExplorePOI(List exploreWayList, IMogoMarkerClickListener clickListener) {
+ try {
+ if (exploreWayList != null) {
+ for (MarkerExploreWay markerExploreWay : exploreWayList) {
+ // 因为目前探路卡片不支持直播,所以这里做了过滤 @李小鹏
+ if (!markerExploreWay.getCanLive()) {
+ MarkerLocation markerLocation = markerExploreWay.getLocation();
+
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setBindObj(markerExploreWay);
+ markerShowEntity.setMarkerLocation(markerLocation);
+ markerShowEntity.setMarkerType(markerExploreWay.getType());
+ markerShowEntity.setTextContent(markerExploreWay.getAddr());
+
+ drawableMarker(
+ V2XServiceManager.getContext(),
+ markerShowEntity,
+ clickListener);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearExplorePOI() {
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_CARD_TYPE_ROAD_CONDITION);
+ }
+
+ @Override
+ public void drawableNoveltyPOI(List noveltyInfoList, IMogoMarkerClickListener clickListener) {
+ try {
+ if (noveltyInfoList != null) {
+ for (MarkerNoveltyInfo noveltyInfo : noveltyInfoList) {
+ MarkerLocation markerLocation = noveltyInfo.getLocation();
+
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setBindObj(noveltyInfo);
+ markerShowEntity.setMarkerLocation(markerLocation);
+ markerShowEntity.setMarkerType(noveltyInfo.getType());
+ markerShowEntity.setTextContent(noveltyInfo.getLocation().getAddress());
+
+ // 这里只绘制道路事件相关
+ switch (noveltyInfo.getPoiType()) {
+ case V2XPoiTypeEnum.TRAFFIC_CHECK:
+ case V2XPoiTypeEnum.ROAD_CLOSED:
+ case V2XPoiTypeEnum.FOURS_ROAD_WORK:
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ case V2XPoiTypeEnum.FOURS_PONDING:
+ case V2XPoiTypeEnum.FOURS_PARKING:
+ case V2XPoiTypeEnum.FOURS_ICE:
+ case V2XPoiTypeEnum.FOURS_FOG:
+ case V2XPoiTypeEnum.FOURS_ACCIDENT:
+ drawableMarker(
+ V2XServiceManager.getContext(),
+ markerShowEntity,
+ clickListener);
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearNoveltyPOI() {
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_CARD_TYPE_NOVELTY);
+ }
+
+ @Override
+ public void drawableMarker(Context context, MarkerShowEntity markerShowEntity, IMogoMarkerClickListener clickListener) {
+// Logger.i(MODULE_NAME, "绘制Marker====drawMapMarker:" + markerShowEntity);
+ try {
+ if (markerShowEntity.getMarkerLocation() != null) {
+ MogoMarkerOptions options = new MogoMarkerOptions()
+ .object(markerShowEntity)
+ .latitude(markerShowEntity.getMarkerLocation().getLat())
+ .longitude(markerShowEntity.getMarkerLocation().getLon());
+
+ // 这里对Marker做下持有者转换,与大而全的区分开,由于绘制的时候用到了低层能力所以不去修改markerShowEntity中的type
+ switch (markerShowEntity.getMarkerType()) {
+ case ServiceConst.CARD_TYPE_USER_DATA:
+ options.owner(V2XConst.V2X_CARD_TYPE_USER_DATA);
+ break;
+ case ServiceConst.CARD_TYPE_NOVELTY:
+ options.owner(V2XConst.V2X_CARD_TYPE_NOVELTY);
+ break;
+ case ServiceConst.CARD_TYPE_ROAD_CONDITION:
+ options.owner(V2XConst.V2X_CARD_TYPE_ROAD_CONDITION);
+ break;
+ case V2XConst.V2X_MARKER_SPECIAL_CAR:
+ options.owner(V2XConst.V2X_MARKER_SPECIAL_CAR);
+ break;
+ case V2XConst.V2X_MARKER_LIVE_CAR:
+ options.owner(V2XConst.V2X_MARKER_LIVE_CAR);
+ break;
+ default:
+ options.owner(markerShowEntity.getMarkerType());
+ break;
+ }
+
+ IMogoMarker marker;
+ Bitmap bitmap;
+ if (markerShowEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_USER_DATA)
+ || markerShowEntity.getMarkerType().equals(V2XConst.V2X_MARKER_SPECIAL_CAR)
+ || markerShowEntity.getMarkerType().equals(V2XConst.V2X_MARKER_LIVE_CAR)
+ || markerShowEntity.getMarkerType().equals(V2XConst.V2X_MARKER_EXPRESS)
+ ) {
+ bitmap = V2XMarkerAdapter.getV2XCarMarkerView(context, markerShowEntity);
+ options.icon(bitmap);
+ marker = V2XServiceManager.getMarkerManager().addMarker(markerShowEntity.getMarkerType(), options);
+ } else {
+ IMarkerView iMarkerView = MapMarkerAdapter.getMarkerView(context, markerShowEntity, options);
+ bitmap = ViewUtils.fromView(iMarkerView.getView());
+ options.icon(bitmap);
+ marker = V2XServiceManager.getMarkerManager().addMarker(markerShowEntity.getMarkerType(), options);
+ iMarkerView.setMarker(marker);
+ }
+ //marker.setOnMarkerClickListener(clickListener);
+ } else {
+ Logger.e(MODULE_NAME, "Location 必须进行初始化!!!!!");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public IMogoMarker openMarker(Context context, IMogoMarker currentMarker) {
+ try {
+ if (currentMarker != null) {
+ Object object = currentMarker.getObject();
+ if (object != null) {
+ // 修改数据
+ MarkerShowEntity showEntity = (MarkerShowEntity) object;
+ showEntity.setChecked(true);
+
+ // 获取数据对应的View
+ IMarkerView markerView = MapMarkerAdapter.getMarkerView(context,
+ showEntity,
+ currentMarker.getMogoMarkerOptions());
+
+ Bitmap bitmap;
+ if (showEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_USER_DATA)
+ || showEntity.getMarkerType().equals(V2XConst.V2X_MARKER_SPECIAL_CAR)) {
+ bitmap = V2XMarkerAdapter.getV2XCarMarkerView(context, showEntity);
+ } else {
+ bitmap = ViewUtils.fromView(markerView.getView());
+ }
+
+ currentMarker.setIcon(bitmap);
+ currentMarker.setToTop();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return currentMarker;
+ }
+
+ @Override
+ public void closeMarker(Context context, IMogoMarker currentMarker) {
+ try {
+ if (currentMarker != null) {
+ Object object = currentMarker.getObject();
+ if (object != null) {
+ MarkerShowEntity showEntity = (MarkerShowEntity) object;
+ showEntity.setChecked(false);
+ IMarkerView markerView = MapMarkerAdapter.getMarkerView(context,
+ showEntity,
+ currentMarker.getMogoMarkerOptions());
+
+ Bitmap bitmap;
+ if (showEntity.getMarkerType().equals(ServiceConst.CARD_TYPE_USER_DATA)
+ || showEntity.getMarkerType().equals(V2XConst.V2X_MARKER_SPECIAL_CAR)) {
+ bitmap = V2XMarkerAdapter.getV2XCarMarkerView(context, showEntity);
+ } else {
+ bitmap = ViewUtils.fromView(markerView.getView());
+ }
+ currentMarker.setIcon(bitmap);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void drawableAlarmPOI(Context context, V2XRoadEventEntity roadEventEntity, IMogoMarkerClickListener clickListener) {
+ try {
+ MarkerUtils.resetMapZoom(15);
+ V2XServiceManager.getMapUIController().changeMapMode(EnumMapUI.NorthUP_2D);
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventPOIShow(TAG, true);
+ //Logger.i(MODULE_NAME, "绘制道路事件====drawableAlarmPOI:");
+ // 清除原来的大而全的新鲜事儿
+ clearALLPOI();
+ if (roadEventEntity.getLocation() != null) {
+ // 道路事件,或者水波纹扩散效果
+ MogoMarkerOptions optionsRipple = new MogoMarkerOptions()
+ .object(roadEventEntity)
+ .latitude(roadEventEntity.getLocation().getLat())
+ .longitude(roadEventEntity.getLocation().getLon());
+ optionsRipple.anchor(0.5f, 0.5f);
+
+ // 由于性能问题,D车机不使用事件扩散动画
+ optionsRipple.icon(V2XMarkerAdapter.getV2XRoadEventViewPng(context, roadEventEntity));
+
+ mAlarmInfoMarker = V2XServiceManager.getMarkerManager().addMarker(V2X_EVENT_ALARM_POI, optionsRipple);
+ // 当前Marker设置为最上面
+ mAlarmInfoMarker.setToTop();
+// if (clickListener != null) {
+// mAlarmInfoMarker.setOnMarkerClickListener(clickListener);
+// }
+ // 绘制连接线
+ V2XServiceManager.getMoGoV2XPolylineManager().drawablePolyline(context, roadEventEntity);
+ } else {
+ Logger.e(MODULE_NAME, "Location 必须进行初始化!!!!!");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearAlarmPOI() {
+ boolean isRoadEventPOIShow = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventPOIShow();
+ if (isRoadEventPOIShow) {
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventPOIShow(TAG, false);
+ if (mAlarmInfoMarker != null) {
+ mAlarmInfoMarker.remove();
+ }
+ }
+ }
+
+ @Override
+ public void clearALLPOI() {
+ try {
+ V2XServiceManager.getMarkerManager().removeMarkers();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void init(Context context) {
+
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XPolylineManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XPolylineManager.java
new file mode 100644
index 0000000000..ffbcecf49e
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XPolylineManager.java
@@ -0,0 +1,104 @@
+package com.mogo.module.v2x.manager.impl;
+
+import android.content.Context;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.overlay.IMogoPolyline;
+import com.mogo.map.overlay.MogoPolylineOptions;
+import com.mogo.module.v2x.MoGoV2XServicePaths;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.manager.IMoGoV2XPolylineManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 10:00 PM
+ * desc : 当前车辆与道路事件的连接线
+ * version: 1.0
+ */
+@Route(path = MoGoV2XServicePaths.PATH_V2X_POLYLINE_MANAGER)
+public class MoGoV2XPolylineManager implements IMoGoV2XPolylineManager {
+ private static final String TAG = "MoGoV2XPolylineManager";
+ private static IMogoPolyline mMogoPolyline;
+
+ @Override
+ public void drawablePolyline(Context context, V2XRoadEventEntity roadEventEntity) {
+ try {
+ if (mMogoPolyline != null) {
+ mMogoPolyline.remove();
+ }
+ if ((V2XServiceManager.getMoGoV2XStatusManager().isRoadEventPOIShow()
+ || V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpPOIShow())
+ && V2XServiceManager.getV2XStatusManager().getTargetMoGoLatLng() != null) {
+ // 连接线参数
+ MogoPolylineOptions options = new MogoPolylineOptions();
+
+ // 渐变色
+ List colors = new ArrayList<>();
+
+ switch (roadEventEntity.getPoiType()) {
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_SUGGEST:
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_WARNING:
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ colors.add(0xFFFA8C34);
+ colors.add(0xFFBD6D36);
+ colors.add(0xFFFA8C34);
+ break;
+ default:
+ colors.add(0xFFF95959);
+ colors.add(0xFF942B48);
+ colors.add(0xFFCB253A);
+ break;
+ }
+
+ // 线条粗细,渐变,渐变色值
+ options.width(10).useGradient(true).colorValues(colors);
+
+ // 当前车辆位置
+ MogoLatLng carLocation = V2XServiceManager.getNavi().getCarLocation();
+ if (carLocation != null) {
+ options.add(carLocation);
+ } else {
+ options.add(V2XServiceManager.getV2XStatusManager().getLocation());
+ }
+ // 目标车辆位置
+ options.add(V2XServiceManager.getV2XStatusManager().getTargetMoGoLatLng());
+
+ // 绘制线的对象
+ mMogoPolyline = V2XServiceManager.getMogoOverlayManager().addPolyline(options);
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearLine() {
+ if (mMogoPolyline != null) {
+ mMogoPolyline.remove();
+ mMogoPolyline = null;
+ V2XServiceManager.getV2XStatusManager().setAlarmInfo(null);
+ }
+ }
+
+ @Override
+ public void init(Context context) {
+
+ }
+
+ /**
+ * @return 绘制连接线的对象
+ */
+ @Override
+ public IMogoPolyline getMogoPolyline() {
+ return mMogoPolyline;
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XStatusManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XStatusManager.java
new file mode 100644
index 0000000000..e45906f085
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/manager/impl/MoGoV2XStatusManager.java
@@ -0,0 +1,256 @@
+package com.mogo.module.v2x.manager.impl;
+
+import android.content.Context;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.mogo.module.v2x.MoGoV2XServicePaths;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.manager.IMoGoV2XStatusChangedListener;
+import com.mogo.module.v2x.manager.IMoGoV2XStatusManager;
+import com.mogo.module.v2x.manager.V2XStatusDescriptor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/17 7:34 PM
+ * desc :
+ * version: 1.0
+ */
+@Route(path = MoGoV2XServicePaths.PATH_V2X_STATUS_MANAGER)
+public class MoGoV2XStatusManager implements IMoGoV2XStatusManager {
+ private static final String TAG = "MoGoV2XStatusManager";
+
+ /**
+ * 状态记录
+ */
+ private static final Map mStatus = new ConcurrentHashMap<>();
+
+ /**
+ * 回调集合
+ */
+ private static final Map> mListeners = new ConcurrentHashMap<>();
+
+ /**
+ * 状态类型修改记录
+ */
+ private static final Map mModifier = new ConcurrentHashMap<>();
+
+ // 查询状态存储情况
+ private boolean get_bool_val(V2XStatusDescriptor descriptor) {
+ Boolean val = mStatus.get(descriptor);
+ return val == null ? false : val;
+ }
+
+ @Override
+ public boolean isRoadEventPOIShow() {
+ return get_bool_val(V2XStatusDescriptor.RoadEventPOI_UI);
+ }
+
+ @Override
+ public boolean isRoadEventButtonShow() {
+ return get_bool_val(V2XStatusDescriptor.RoadEventButton_UI);
+ }
+
+ @Override
+ public boolean isRoadEventWindowShow() {
+ return get_bool_val(V2XStatusDescriptor.RoadEventWindow_UI);
+ }
+
+ @Override
+ public boolean isRoadLiveCarWindowShow() {
+ return get_bool_val(V2XStatusDescriptor.RoadLiveCarWindow_UI);
+ }
+
+ @Override
+ public boolean isOtherSeekHelpWindowShow() {
+ return get_bool_val(V2XStatusDescriptor.OtherSeekHelpWindow_UI);
+ }
+
+ @Override
+ public boolean isMeSeekHelpButtonShow() {
+ return get_bool_val(V2XStatusDescriptor.MeSeekHelpButton_UI);
+ }
+
+ @Override
+ public boolean isOtherSeekHelpPOIShow() {
+ return get_bool_val(V2XStatusDescriptor.OtherSeekHelpPOI_UI);
+ }
+
+ @Override
+ public boolean isV2XAnimationShow() {
+ return get_bool_val(V2XStatusDescriptor.V2XAnimationWindow_UI);
+ }
+
+ @Override
+ public boolean isLeftLiveVideoShow() {
+ return get_bool_val(V2XStatusDescriptor.LiveCarWindow_UI);
+ }
+
+ @Override
+ public boolean isPushWindowShow() {
+ return get_bool_val(V2XStatusDescriptor.PushWindow_UI);
+ }
+
+ @Override
+ public boolean isPushPOIShow() {
+ return get_bool_val(V2XStatusDescriptor.PushWindowPOI_UI);
+ }
+
+ @Override
+ public boolean isFatigueDrivingWindowShow() {
+ return get_bool_val(V2XStatusDescriptor.FatigueDrivingWindow_UI);
+ }
+
+ @Override
+ public void setRoadEventPOIShow(String tag, boolean show) {
+ V2XServiceManager.getMoGoStatusManager().setV2XUIShow(V2XConst.MODULE_NAME, show);
+ mStatus.put(V2XStatusDescriptor.RoadEventPOI_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.RoadEventPOI_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.RoadEventPOI_UI);
+ }
+
+ @Override
+ public void setRoadEventButtonShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.RoadEventButton_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.RoadEventButton_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.RoadEventButton_UI);
+ }
+
+ @Override
+ public void setRoadEventWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.RoadEventWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.RoadEventWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.RoadEventWindow_UI);
+ }
+
+ @Override
+ public void setRoadLiveCarWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.RoadLiveCarWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.RoadLiveCarWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.RoadLiveCarWindow_UI);
+ }
+
+ @Override
+ public void setOtherSeekHelpWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.OtherSeekHelpWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.OtherSeekHelpWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.OtherSeekHelpWindow_UI);
+ }
+
+ @Override
+ public void setMeSeekHelpButtonShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.MeSeekHelpButton_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.MeSeekHelpButton_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.MeSeekHelpButton_UI);
+ }
+
+ @Override
+ public void setOtherSeekHelpPOIShow(String tag, boolean show) {
+ V2XServiceManager.getMoGoStatusManager().setV2XUIShow(V2XConst.MODULE_NAME, show);
+ mStatus.put(V2XStatusDescriptor.OtherSeekHelpPOI_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.OtherSeekHelpPOI_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.OtherSeekHelpPOI_UI);
+ }
+
+ @Override
+ public void setV2XAnimationWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.V2XAnimationWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.V2XAnimationWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.V2XAnimationWindow_UI);
+ }
+
+ @Override
+ public void setLiveCarWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.LiveCarWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.LiveCarWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.LiveCarWindow_UI);
+ }
+
+
+ @Override
+ public void setPushWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.PushWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.PushWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.PushWindow_UI);
+ }
+
+ @Override
+ public void setPushPOIShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.PushWindowPOI_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.PushWindowPOI_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.PushWindowPOI_UI);
+ }
+
+ @Override
+ public void setFatigueDrivingWindowShow(String tag, boolean show) {
+ mStatus.put(V2XStatusDescriptor.FatigueDrivingWindow_UI, show);
+ invokeStatusChangedListener(V2XStatusDescriptor.FatigueDrivingWindow_UI, show);
+ recordStatusModifier(tag, V2XStatusDescriptor.FatigueDrivingWindow_UI);
+ }
+
+ @Override
+ public void registerStatusChangedListener(String tag, V2XStatusDescriptor descriptor, IMoGoV2XStatusChangedListener listener) {
+ if (listener == null || descriptor == null) {
+ return;
+ }
+ if (!mListeners.containsKey(descriptor)) {
+ mListeners.put(descriptor, new ArrayList<>());
+ }
+ if (mListeners.get(descriptor) == null) {
+ mListeners.put(descriptor, new ArrayList<>());
+ }
+ List listeners = mListeners.get(descriptor);
+ if (listeners != null) {
+ listeners.add(listener);
+ }
+ }
+
+ @Override
+ public void unregisterStatusChangedListener(String tag, V2XStatusDescriptor descriptor, IMoGoV2XStatusChangedListener listener) {
+ List listeners = mListeners.get(descriptor);
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+
+
+ /**
+ * 调用所有存储的监听
+ *
+ * @param descriptor
+ * @param status
+ */
+ private void invokeStatusChangedListener(V2XStatusDescriptor descriptor, boolean status) {
+ if (mListeners.containsKey(descriptor)) {
+ List listeners = mListeners.get(descriptor);
+ if (listeners != null) {
+ for (IMoGoV2XStatusChangedListener listener : listeners) {
+ if (listener != null) {
+ listener.onStatusChanged(descriptor, status);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 记录状态
+ *
+ * @param tag
+ * @param descriptor
+ */
+ private void recordStatusModifier(String tag, V2XStatusDescriptor descriptor) {
+ mModifier.put(descriptor, tag);
+ }
+
+ @Override
+ public void init(Context context) {
+
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerAdapter.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerAdapter.java
new file mode 100644
index 0000000000..2e8cf7d8a1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerAdapter.java
@@ -0,0 +1,147 @@
+package com.mogo.module.v2x.marker;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.v2x.R;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+
+import java.util.ArrayList;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-1015:55
+ * desc : V2X 地图气泡
+ * version: 1.0
+ */
+public class V2XMarkerAdapter {
+
+ /**
+ * 返回道路事件
+ */
+ public static Bitmap getV2XRoadEventMarkerView(Context context, V2XRoadEventEntity alarmInfo) {
+ return new V2XMarkerRoadEventView(context, alarmInfo).getView();
+ }
+
+ /**
+ * 返回道路事件
+ */
+ public static Bitmap getV2XRoadEventMarkerView(Context context, V2XRoadEventEntity alarmInfo, int imageRes) {
+ return new V2XMarkerRoadEventView(context, alarmInfo).setBackground(imageRes).getView();
+ }
+
+ /**
+ * 返回道路事件静态的图,因为D车机性能不行,会卡顿
+ */
+ public static Bitmap getV2XRoadEventViewPng(Context context, V2XRoadEventEntity alarmInfo) {
+ Bitmap bitmap;
+ switch (alarmInfo.getPoiType()) {
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_SUGGEST:
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_WARNING:
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ bitmap = getV2XRoadEventMarkerView(
+ context,
+ alarmInfo,
+ R.drawable.v_to_x_warning_circle_orange_00009);
+ break;
+ default:
+ bitmap = getV2XRoadEventMarkerView(
+ context,
+ alarmInfo,
+ R.drawable.v_to_x_warning_circle_red_00009);
+ break;
+ }
+ return bitmap;
+ }
+
+ /**
+ * 返回道路事件gif序列图集合
+ */
+ public static ArrayList getV2XRoadEventViewGif(Context context, V2XRoadEventEntity alarmInfo) {
+ ArrayList bitmapArrayList;
+ switch (alarmInfo.getPoiType()) {
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_SUGGEST:
+ case V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_WARNING:
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ bitmapArrayList = getV2XRoadEventOrangeMarkerView(context, alarmInfo);
+ break;
+ default:
+ bitmapArrayList = getV2XRoadEventRedMarkerView(context, alarmInfo);
+ break;
+ }
+ return bitmapArrayList;
+ }
+
+ /**
+ * 返回红色扩散效果的序列
+ */
+ public static ArrayList getV2XRoadEventRedMarkerView(Context context, V2XRoadEventEntity alarmInfo) {
+ ArrayList icons = new ArrayList<>();
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00000));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00001));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00002));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00003));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00004));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00005));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00006));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00007));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00008));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00009));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00010));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00011));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00012));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00013));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00015));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00017));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00018));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00020));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00023));
+ return icons;
+ }
+
+ /**
+ * 返回橘色色扩散效果的序列
+ */
+ public static ArrayList getV2XRoadEventOrangeMarkerView(Context context, V2XRoadEventEntity alarmInfo) {
+ ArrayList icons = new ArrayList<>();
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00000));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00001));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00002));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00003));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00004));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00005));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00006));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00007));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00008));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00009));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00010));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00011));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00012));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00013));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00015));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00017));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00018));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00019));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00020));
+ icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00023));
+ return icons;
+ }
+
+ /**
+ * 获取模拟点
+ *
+ * @param context 上下文
+ * @return MarkerView
+ */
+ public static Bitmap getV2XCarMarkerView(Context context, MarkerShowEntity showEntity) {
+ if (showEntity.isChecked()) {
+ return new V2XMarkerCarInfoView(context, showEntity).getView();
+ } else {
+ return new V2XMarkerCarView(context, showEntity).getView();
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarInfoView.kt b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarInfoView.kt
new file mode 100644
index 0000000000..6ed65b7a18
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarInfoView.kt
@@ -0,0 +1,145 @@
+package com.mogo.module.v2x.marker
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.mogo.module.common.entity.MarkerOnlineCar
+import com.mogo.module.common.entity.MarkerShowEntity
+import com.mogo.module.service.utils.ViewUtils
+import com.mogo.module.v2x.R
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity
+import com.mogo.module.common.entity.V2XPoiTypeEnum
+import kotlinx.android.synthetic.main.view_marker_car.view.*
+import kotlinx.android.synthetic.main.view_marker_car_info.view.*
+import kotlinx.android.synthetic.main.view_marker_car_info.view.ivCar
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-0619:55
+ * desc : 绘制在线车辆,特殊车辆
+ * version: 1.0
+ */
+class V2XMarkerCarInfoView(context: Context, showEntity: MarkerShowEntity) :
+ ConstraintLayout(context) {
+
+ init {
+ initView(context, showEntity)
+ }
+
+ private fun initView(context: Context, showEntity: MarkerShowEntity) {
+ val bindObj: Any = showEntity.bindObj
+ if (bindObj is MarkerOnlineCar) {
+ //1 老司机 2 安全驾驶 3 危险驾驶 4 可直播车辆
+ when (bindObj.userInfo.safeLabelType) {
+ // 可直播车机
+ 4 -> {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_car, this)
+ ivMarkerTip.setImageResource(R.drawable.v_to_x_marker_car_live_vedio)
+ }
+ else -> {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_car_info, this)
+ }
+ }
+ }
+ if (bindObj is V2XMarkerEntity) {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_car, this)
+ }
+ updateUI(showEntity)
+ }
+
+ fun updateUI(showEntity: MarkerShowEntity) {
+ ivCar.rotation = showEntity.markerLocation.angle.toFloat()
+// ivCar.rotation = 90f
+
+ tvUserMarker.text = if (TextUtils.isEmpty(showEntity.textContent)) {
+ ""
+ } else {
+ showEntity.textContent
+ }
+
+ val bindObj: Any = showEntity.bindObj
+ if (bindObj is MarkerOnlineCar) {
+ tvMarkerContent.text =
+ if (bindObj.userInfo == null && TextUtils.isEmpty(bindObj.userInfo.userName)) {
+ "蘑菇车主"
+ } else {
+ bindObj.userInfo.userName
+ }
+
+ //车辆类型,0-普通车辆,1-警车,2-救护车,3-道路救援车辆',
+ when (bindObj.carInfo.vehicleType) {
+ // 普通车
+ 0 -> {
+ clMarkerContent.visibility = View.VISIBLE
+ ivReverseTriangle.visibility = View.VISIBLE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ // 警车
+ 1 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_police)
+ }
+ // 救护车
+ 2 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_ambulance)
+ }
+ // 道路救援车辆
+ 3 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ else -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ }
+ }
+ if (bindObj is V2XMarkerEntity) {
+ when (bindObj.targetId) {
+ 10001 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ 10002 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_ambulance)
+ }
+ 10003 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_police)
+ }
+ //失控车
+ 10004 -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ // 故障车
+ V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING -> {
+ clMarkerContent.visibility = View.GONE
+ ivReverseTriangle.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ }
+ }
+ }
+
+ fun getView(): Bitmap {
+ return ViewUtils.fromView(this)
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarView.kt b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarView.kt
new file mode 100644
index 0000000000..d283ff7692
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerCarView.kt
@@ -0,0 +1,115 @@
+package com.mogo.module.v2x.marker
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.view.LayoutInflater
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.mogo.module.common.entity.MarkerOnlineCar
+import com.mogo.module.common.entity.MarkerShowEntity
+import com.mogo.module.service.utils.ViewUtils
+import com.mogo.module.v2x.R
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity
+import com.mogo.module.common.entity.V2XPoiTypeEnum
+import kotlinx.android.synthetic.main.view_marker_car.view.*
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-0619:55
+ * desc : 绘制在线车辆,特殊车辆
+ * version: 1.0
+ */
+class V2XMarkerCarView(context: Context, showEntity: MarkerShowEntity) :
+ ConstraintLayout(context) {
+
+ init {
+ initView(context, showEntity)
+ }
+
+ private fun initView(context: Context, showEntity: MarkerShowEntity) {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_car, this)
+ updateUI(showEntity)
+ }
+
+ fun updateUI(showEntity: MarkerShowEntity) {
+ ivCar.rotation = showEntity.markerLocation.angle.toFloat()
+
+ val bindObj: Any = showEntity.bindObj
+ if (bindObj is MarkerOnlineCar) {
+ //1 老司机 2 安全驾驶 3 危险驾驶 4 可直播车辆
+ when (bindObj.userInfo.safeLabelType) {
+ 1 -> {
+ ivMarkerTip.setImageResource(R.drawable.v_to_x_marker_car_blue)
+ }
+ 2 -> {
+ ivMarkerTip.setImageResource(R.drawable.v_to_x_marker_car_green)
+ }
+ 3 -> {
+ ivMarkerTip.setImageResource(R.drawable.v_to_x_marker_car_red)
+ }
+ 4 -> {
+ ivMarkerTip.setImageResource(R.drawable.v_to_x_marker_car_live_vedio)
+ }
+ }
+
+ //车辆类型,0-普通车辆,1-警车,2-救护车,3-道路救援车辆',
+ when (bindObj.carInfo.vehicleType) {
+ // 普通车
+ 0 -> {
+ ivMarkerTip.visibility = View.VISIBLE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ // 警车
+ 1 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_police)
+ }
+ // 救护车
+ 2 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_ambulance)
+ }
+ // 道路救援车辆
+ 3 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ else -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ }
+ }
+ if (bindObj is V2XMarkerEntity) {
+ when (bindObj.targetId) {
+ 10001 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_gray)
+ }
+ 10002 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_ambulance)
+ }
+ 10003 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.icon_car_police)
+ }
+ 10004 -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ // 故障车
+ V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING -> {
+ ivMarkerTip.visibility = View.GONE
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ }
+ }
+ }
+
+ fun getView(): Bitmap {
+ return ViewUtils.fromView(this)
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerRoadEventView.kt b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerRoadEventView.kt
new file mode 100644
index 0000000000..3059bcd6a7
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/marker/V2XMarkerRoadEventView.kt
@@ -0,0 +1,126 @@
+package com.mogo.module.v2x.marker
+
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.view.LayoutInflater
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.mogo.module.service.utils.ViewUtils
+import com.mogo.module.v2x.R
+import com.mogo.module.common.entity.V2XPoiTypeEnum
+import com.mogo.module.common.entity.V2XRoadEventEntity
+import kotlinx.android.synthetic.main.view_marker_event_car.view.*
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-0619:55
+ * desc :
+ * 3、道路事件
+ * 2.18 演示 :驾驶模式中地图展示“拥堵“、“施工”;
+ * (ADAS模式下还包含 原有的拥堵、交通检查、封路事件)
+ * version: 1.0
+ */
+class V2XMarkerRoadEventView(context: Context, alarmInfo: V2XRoadEventEntity) :
+ ConstraintLayout(context) {
+ val TAG = "V2XMarkerRoadEventView"
+
+ init {
+ initView(context, alarmInfo)
+ }
+
+ fun initView(context: Context, alarmInfo: V2XRoadEventEntity) {
+ if (alarmInfo.poiType == V2XPoiTypeEnum.ALERT_FRONT_CAR ||
+ alarmInfo.poiType == V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING.toString()
+ ) {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_event_car, this)
+ } else {
+ LayoutInflater.from(context)
+ .inflate(R.layout.view_marker_event_road, this)
+ }
+ updateIcon(alarmInfo)
+ }
+
+ /**
+ * @see V2XPoiTypeEnum
+ */
+ private fun updateIcon(alarmInfo: V2XRoadEventEntity) {
+ //Logger.d(MODULE_NAME, alarmInfo.toString())
+ // 道路施工、积水、路面结冰、浓雾、事故、拥堵
+ when (alarmInfo.poiType) {
+ //交通检查
+ V2XPoiTypeEnum.TRAFFIC_CHECK -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_2)
+ }
+ //封路
+ V2XPoiTypeEnum.ROAD_CLOSED -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_16)
+ }
+ //施工
+ V2XPoiTypeEnum.FOURS_ROAD_WORK -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_11)
+ }
+ //拥堵
+ V2XPoiTypeEnum.FOURS_BLOCK_UP -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_5)
+ }
+ //积水
+ V2XPoiTypeEnum.FOURS_PONDING -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_6)
+ }
+ //浓雾
+ V2XPoiTypeEnum.FOURS_FOG -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_9)
+ }
+ //结冰
+ V2XPoiTypeEnum.FOURS_ICE -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_8)
+ }
+ //事故
+ V2XPoiTypeEnum.FOURS_ACCIDENT -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_7)
+ }
+ //红绿灯数据
+ V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_SUGGEST -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_3)
+ }
+ //红绿灯数据
+ V2XPoiTypeEnum.ALERT_TRAFFIC_LIGHT_WARNING -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_3)
+ }
+ //前方静止or慢速车辆报警
+ V2XPoiTypeEnum.ALERT_FRONT_CAR -> {
+ ivCar.setImageResource(R.drawable.v_to_x_warning_car_red)
+ }
+ // 故障车辆
+ V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING.toString() -> {
+ ivCar.setImageResource(R.drawable.icon_car_red)
+ ivCarTop.visibility = View.VISIBLE
+ }
+ // 取快递
+ V2XPoiTypeEnum.ALERT_TRAFFIC_EXPRESS -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_express)
+ ivBg.visibility = View.GONE
+ }
+ // 顺风车
+ V2XPoiTypeEnum.ALERT_TRAFFIC_TAXI -> {
+ ivCar.setImageResource(R.drawable.v_to_x_marker_taxi)
+ ivBg.visibility = View.GONE
+ }
+ }
+ }
+
+ /**
+ * 背景
+ */
+ fun setBackground(imageRes: Int): V2XMarkerRoadEventView {
+ ivBg.setImageResource(imageRes)
+ return this
+ }
+
+ fun getView(): Bitmap {
+ return ViewUtils.fromView(this)
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/HttpConstant.kt b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/HttpConstant.kt
new file mode 100644
index 0000000000..dcc0b492d6
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/HttpConstant.kt
@@ -0,0 +1,23 @@
+package com.mogo.module.v2x.network
+
+import com.mogo.commons.debug.DebugConfig
+
+class HttpConstant {
+
+ companion object {
+ const val HOST_DEV = "http://dzt-test.zhidaohulian.com"
+ const val HOST_TEST = "http://dzt-test.zhidaohulian.com"
+ const val HOST_DEMO = "http://dzt-show.zhidaohulian.com"
+ const val HOST_PRODUCT = "https://dzt.zhidaohulian.com"
+
+ fun getNetHost(): String {
+ return when (DebugConfig.getNetMode()) {
+ DebugConfig.NET_MODE_DEV -> HOST_DEV
+ DebugConfig.NET_MODE_QA -> HOST_TEST
+ DebugConfig.NET_MODE_DEMO -> HOST_DEMO
+ else -> HOST_PRODUCT
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XApiService.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XApiService.java
new file mode 100644
index 0000000000..40e84f3b7d
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XApiService.java
@@ -0,0 +1,111 @@
+package com.mogo.module.v2x.network;
+
+import com.mogo.commons.data.BaseData;
+import com.mogo.module.common.entity.MarkerCardResult;
+import com.mogo.module.common.entity.MarkerResponse;
+import com.mogo.module.v2x.entity.net.V2XUserInfoRes;
+import com.mogo.module.v2x.entity.net.V2XDemoUserInfoRes;
+import com.mogo.module.v2x.entity.net.V2XLiveCarRes;
+import com.mogo.module.v2x.entity.net.V2XLivePushVoRes;
+import com.mogo.module.v2x.entity.net.V2XSeekHelpRes;
+import com.mogo.module.v2x.entity.net.V2XStrategyPushRes;
+
+import java.util.Map;
+
+import io.reactivex.Observable;
+import okhttp3.RequestBody;
+import retrofit2.http.Body;
+import retrofit2.http.FieldMap;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.GET;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+
+/**
+ * @author congtaowang
+ * @since 2020-01-03
+ *
+ * 接口描述
+ */
+public interface V2XApiService {
+ /**
+ * 直播心跳
+ */
+ @FormUrlEncoded
+ @POST("/dataService/integratedServices/app/push/no/heartbeat/v1")
+ Observable refreshHeartBeat(@FieldMap Map liveBroadcast);
+
+ /**
+ * 刷新地图气泡点
+ */
+ @FormUrlEncoded
+ @POST("/yycp-launcherSnapshot/launcherSnapshot/querySnapshotAsync")
+ Observable querySnapshotAsync(@FieldMap Map parameters);
+
+ /**
+ * 直播点赞
+ */
+ @FormUrlEncoded
+ @POST("/yycp-geo-fence-carService/restrictedRules/car/liveBroadcastPraise")
+ Observable giveLikeLiveVideo(@FieldMap Map parameters);
+
+ /**
+ * 同过SN获取用户信息
+ */
+ @Headers({"Content-Type:application/json", "Accept:application/json"})
+ @POST("/yycp-realtimeLocations/realTimeLocationServer/queryUserInfoBySn")
+ Observable queryUserInfoBySn(@Body RequestBody jsonStr);
+
+ /**
+ * 车辆故障求助查询
+ *
+ * @param param
+ * @return
+ */
+ @FormUrlEncoded
+ @POST("/yycp-realtimeLocations/vehicleTypeManage/car/queryVehicleType/v1")
+ Observable queryHelpSignal(@FieldMap Map param);
+
+ /**
+ * 车辆故障求助查询
+ *
+ * @param param
+ * @return
+ */
+ @FormUrlEncoded
+ @POST("/yycp-realtimeLocations/vehicleTypeManage/car/updateVehicleType/v1")
+ Observable sendHelpSignal(@FieldMap Map param);
+
+ /**
+ * 根据经纬度查询附近可直播车机直播信息
+ */
+ @FormUrlEncoded
+ @POST("/yycp-realtimeLocations/realTimeLocationServer/car/queryNearbyVehicleLiveByLocation/v1")
+ Observable queryNearbyVehicleLiveByLocation(@FieldMap Map parameters);
+
+ /**
+ * 推流与停止推流接口
+ */
+ @FormUrlEncoded
+ @POST("/dataService/integratedServices/app/push/no/livePush/v1")
+ Observable livePush(@FieldMap Map parameters);
+
+ /**
+ * TODO 查询演示车用户信息
+ */
+ @GET("/yycp-launcherSnapshot/mock/getMockUserInfos")
+ Observable getMockUserInfos();
+
+ /**
+ * 根据名称获取策略详情
+ */
+ @GET("/yycp-strategyPush/push/strategy/item?name=TIRE_DRIVING")
+ Observable getStrategyPush();
+
+ /**
+ * 违章地段查询接口
+ */
+ @FormUrlEncoded
+ @POST("/yycp-launcherSnapshot/launcherSnapshot/queryIllegalPark")
+ Observable queryIllegalPark(@FieldMap Map parameters);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshCallback.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshCallback.java
new file mode 100644
index 0000000000..f17d3d6672
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshCallback.java
@@ -0,0 +1,14 @@
+package com.mogo.module.v2x.network;
+
+/**
+ * @author congtaowang
+ * @since 2020-01-03
+ *
+ * 刷新回调
+ */
+public interface V2XRefreshCallback {
+
+ void onSuccess(T result);
+
+ void onFail(String msg);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshModel.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshModel.java
new file mode 100644
index 0000000000..c3bf82a52e
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/network/V2XRefreshModel.java
@@ -0,0 +1,477 @@
+package com.mogo.module.v2x.network;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.alibaba.android.arouter.launcher.ARouter;
+import com.mogo.commons.data.BaseData;
+import com.mogo.commons.network.ParamsProvider;
+import com.mogo.commons.network.SubscribeImpl;
+import com.mogo.commons.network.Utils;
+import com.mogo.map.MogoLatLng;
+import com.mogo.module.common.entity.MarkerResponse;
+import com.mogo.module.service.ServiceConst;
+import com.mogo.module.service.network.RefreshBody;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.entity.net.V2XDemoUserInfoRes;
+import com.mogo.module.v2x.entity.net.V2XLiveCarBroadcastReq;
+import com.mogo.module.v2x.entity.net.V2XLiveCarRes;
+import com.mogo.module.v2x.entity.net.V2XLivePushVoRes;
+import com.mogo.module.v2x.entity.net.V2XSeekHelpRes;
+import com.mogo.module.v2x.entity.net.V2XStrategyPushRes;
+import com.mogo.module.v2x.entity.net.V2XUserInfoRes;
+import com.mogo.service.MogoServicePaths;
+import com.mogo.service.network.IMogoNetwork;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.network.RequestOptions;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.RequestBody;
+
+
+/**
+ * 数据接口API
+ *
+ * @author donghongyu
+ * @since 2020-01-03
+ */
+public class V2XRefreshModel {
+
+ private Context mContext;
+ private V2XApiService mV2XApiService;
+ private static V2XRefreshModel mV2XRefreshModel;
+
+ private V2XRefreshModel() {
+ }
+
+ public synchronized static V2XRefreshModel getInstance(Context context) {
+ if (mV2XRefreshModel == null) {
+ synchronized (V2XRefreshModel.class) {
+ if (mV2XRefreshModel == null) {
+ mV2XRefreshModel = new V2XRefreshModel();
+ mV2XRefreshModel.init(context);
+ }
+ }
+ }
+ return mV2XRefreshModel;
+ }
+
+ private void init(Context context) {
+ this.mContext = context;
+ IMogoNetwork network = (IMogoNetwork) ARouter.getInstance().build(MogoServicePaths.PATH_SERVICES_NETWORK).navigation(context);
+ this.mV2XApiService = network.create(V2XApiService.class, HttpConstant.Companion.getNetHost());
+ }
+
+ /**
+ * 刷新地图点数据
+ */
+ public void querySnapshotAsync(MogoLatLng latLng, int radius, int limit) {
+ if (mV2XApiService != null) {
+ final Map query = new ParamsProvider.Builder(mContext).build();
+ final RefreshBody refreshBody = new RefreshBody();
+ refreshBody.limit = limit;
+ refreshBody.location = new RefreshBody.LatLon(latLng.lat, latLng.lon);
+ refreshBody.radius = radius;
+ refreshBody.dataType.add(ServiceConst.CARD_TYPE_ROAD_CONDITION);
+ refreshBody.viewPush = true;
+ query.put("data", GsonUtil.jsonFromObject(refreshBody));
+ mV2XApiService.querySnapshotAsync(query)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(BaseData o) {
+ super.onSuccess(o);
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ }
+ });
+ }
+ }
+
+ /**
+ * 触发刷新直播心跳
+ *
+ * @param sn 目标车机SN
+ * @param videoChannel 直播的频道
+ * @param callback 回调
+ */
+ public void refreshHeartBeat(String sn, String videoChannel, final V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ Map liveBroadcast = new HashMap<>();
+ liveBroadcast.put("sn", sn);
+ liveBroadcast.put("data", GsonUtil.getGson().toJson(new V2XLiveCarBroadcastReq(sn, videoChannel)));
+
+ mV2XApiService.refreshHeartBeat(liveBroadcast)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(BaseData o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+
+ /**
+ * 直播点赞👍
+ *
+ * @param callback 回调
+ */
+ public void giveLikeLiveVideo(final V2XRefreshCallback callback, String snStr) {
+ if (mV2XApiService != null) {
+ Logger.d(V2XConst.MODULE_NAME, "点赞车机:" + snStr);
+ final Map query = new ParamsProvider.Builder(mContext).build();
+ query.put("data", "{\"sn\":" + snStr + "}");
+ mV2XApiService.giveLikeLiveVideo(query)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(BaseData o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 获取用户信息
+ *
+ * @param sn 目标车机SN
+ */
+ public void queryUserInfoBySn(String sn, final V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ RequestBody body = RequestBody.create(
+ okhttp3.MediaType.parse("application/json; charset=utf-8"),
+ "{\"sn\":\"" + sn + "\"}");
+
+ mV2XApiService.queryUserInfoBySn(body)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XUserInfoRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 根据经纬度查询附近可直播车机直播信息
+ *
+ * @param callback 回调
+ */
+ public void queryNearbyVehicleLiveByLocation(
+ V2XRefreshCallback callback, double lon, double lat) {
+ if (mV2XApiService != null) {
+ final Map query = new ParamsProvider.Builder(mContext).build();
+
+ StringBuffer dataStr = new StringBuffer();
+ dataStr.append("{");
+ dataStr.append("\"lon\":");
+ dataStr.append(lon);
+ dataStr.append(",");
+ dataStr.append("\"lat\":");
+ dataStr.append(lat);
+ dataStr.append(",");
+ dataStr.append("\"radius\":");
+ dataStr.append(0.5);
+ dataStr.append(",");
+ dataStr.append("\"size\":");
+ dataStr.append(5);
+ dataStr.append("}");
+
+ query.put("data", dataStr.toString());
+ mV2XApiService.queryNearbyVehicleLiveByLocation(query)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XLiveCarRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 推流与停止推流接口
+ *
+ * @param callback 回调
+ */
+ public void livePush(V2XRefreshCallback callback, String sn, int playType) {
+ if (mV2XApiService != null) {
+ final Map query = new ParamsProvider.Builder(mContext).build();
+ query.put("data", "{" +
+ "\"eventId\": \"yycp\"," +
+ "\"sn\": \"" + sn + "\"," +
+ "\"type\": \"" + playType + "\"," +
+ "\"videoChannel\": \"C_1\"" +
+ "}");
+ mV2XApiService.livePush(query)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XLivePushVoRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 取消求助
+ *
+ * @param callback
+ */
+ public void cancelHelpSignal(V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ final Map map = new ParamsProvider.Builder(mContext).build();
+ String json = new StringBuilder()
+ .append("{")
+ .append("\"sn\":").append(Utils.getSn())
+ .append(",")
+ .append("\"vehicleType\":")
+ .append(0)
+ .append("}").toString();
+ map.put("data", json);
+ mV2XApiService.sendHelpSignal(map).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(BaseData o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+
+ }
+ }
+
+ /**
+ * 查询当前车辆故障求助状态
+ *
+ * @param callback
+ */
+ public void getHelpSignal(V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ final Map map = new ParamsProvider.Builder(mContext).build();
+ map.put("sn", Utils.getSn());
+ mV2XApiService.queryHelpSignal(map).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XSeekHelpRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+
+ }
+ }
+
+ /**
+ * TODO 演示需求
+ *
+ * @param callback
+ */
+ public void getMockUserInfos(V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ mV2XApiService.getMockUserInfos().subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XDemoUserInfoRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 根据名称获取策略详情
+ */
+ public void getStrategyPush(V2XRefreshCallback callback) {
+ if (mV2XApiService != null) {
+ mV2XApiService.getStrategyPush().subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(V2XStrategyPushRes o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 违章地段查询接口
+ */
+ public void queryIllegalPark(V2XRefreshCallback callback, double lon, double lat) {
+ if (mV2XApiService != null) {
+ final Map map = new ParamsProvider.Builder(mContext).build();
+ String json = "{\"location\":{\"lat\":" + lat + ",\"lon\":" + lon + "},\"radius\":50}";
+// String json = "{\"location\":{\"lat\":39.968139,\"lon\":116.380476},\"radius\":1000}";
+ map.put("data", json);
+ mV2XApiService.queryIllegalPark(map).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new SubscribeImpl(RequestOptions.create(mContext)) {
+ @Override
+ public void onSuccess(MarkerResponse o) {
+ super.onSuccess(o);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ if (callback != null) {
+ if (TextUtils.isEmpty(message)) {
+ message = "网络错误,请稍后重试";
+ }
+ callback.onFail(message);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/receiver/SceneBroadcastReceiver.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/receiver/SceneBroadcastReceiver.java
new file mode 100644
index 0000000000..4966e2dfba
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/receiver/SceneBroadcastReceiver.java
@@ -0,0 +1,32 @@
+package com.mogo.module.v2x.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.scenario.impl.V2XScenarioManager;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+/**
+ * 场景广播接收,道路预警、后台下发、违章停车、故障求助、疲劳驾驶
+ *
+ * @author donghongyu
+ */
+public class SceneBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = V2XConst.MODULE_NAME + "_SceneBroadcastReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ V2XMessageEntity v2XMessageEntity = (V2XMessageEntity) intent.getSerializableExtra("V2XMessageEntity");
+ Logger.d(TAG, "v2XMessageEntity:" + GsonUtil.jsonFromObject(v2XMessageEntity));
+ V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenario.java
new file mode 100644
index 0000000000..89e4de77fc
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenario.java
@@ -0,0 +1,71 @@
+package com.mogo.module.v2x.scenario;
+
+import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
+import com.mogo.module.common.entity.V2XMessageEntity;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 4:13 PM
+ * desc : V2X安全驾驶场景接口
+ * version: 1.0
+ */
+public interface IV2XScenario {
+
+ /**
+ * 展示场景
+ */
+ void show();
+
+ /**
+ * 关闭场景
+ */
+ void close();
+
+ /**
+ * 展示Window
+ */
+ void showWindow();
+
+ /**
+ * 关闭Window
+ */
+ void closeWindow();
+
+ /**
+ * 展示按钮
+ */
+ void showButton();
+
+ /**
+ * 关闭按钮
+ */
+ void closeButton();
+
+ /**
+ * 绘制POI
+ */
+ void drawPOI();
+
+ /**
+ * 清除POI
+ */
+ void clearPOI();
+
+ /**
+ * 是否是相同的场景,如果是说明重复的场景,需要根据场景进行不同的处理
+ *
+ * @param v2XMessageEntity 要比较的场景
+ * @return true-相同的场景,false-不同场景
+ */
+ boolean isSameScenario(V2XMessageEntity v2XMessageEntity);
+
+ /**
+ * 调用小智语音播放TTS
+ *
+ * @param msg 消息
+ * @param callBack 播放回调
+ */
+ void speakTTSVoice(String msg, IMogoVoiceCmdCallBack callBack);
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenarioManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenarioManager.java
new file mode 100644
index 0000000000..2a061a4fca
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/IV2XScenarioManager.java
@@ -0,0 +1,14 @@
+package com.mogo.module.v2x.scenario;
+
+import com.mogo.module.common.entity.V2XMessageEntity;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 3:47 PM
+ * desc : V2X安全驾驶场景管理
+ * version: 1.0
+ */
+public interface IV2XScenarioManager {
+ void handlerMessage(V2XMessageEntity v2XMessageEntity);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/AbsV2XScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/AbsV2XScenario.java
new file mode 100644
index 0000000000..f6c3fe4523
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/AbsV2XScenario.java
@@ -0,0 +1,89 @@
+package com.mogo.module.v2x.scenario.impl;
+
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
+import com.mogo.commons.voice.VoicePreemptType;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.scenario.IV2XScenario;
+import com.mogo.module.v2x.scenario.view.IV2XButton;
+import com.mogo.module.v2x.scenario.view.IV2XMarker;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.manager.IMoGoV2XStatusManager;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.utils.logger.Logger;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:01 PM
+ * desc :
+ * version: 1.0
+ */
+public abstract class AbsV2XScenario implements IV2XScenario {
+ protected String TAG = "AbsV2XScenario";
+ protected IV2XWindow mV2XWindow;
+ protected IV2XButton mV2XButton;
+ protected IV2XMarker mV2XMarker;
+ protected IMoGoV2XStatusManager mV2XStatusManager;
+ protected V2XMessageEntity mV2XMessageEntity;
+
+ protected AbsV2XScenario() {
+ this.mV2XStatusManager = V2XServiceManager.getMoGoV2XStatusManager();
+ }
+
+ public abstract void init(@Nullable V2XMessageEntity v2XMessageEntity);
+
+ @Override
+ public void close() {
+ closeButton();
+ closeWindow();
+ clearPOI();
+ }
+
+ @Override
+ public void speakTTSVoice(@Nullable String msg, IMogoVoiceCmdCallBack callBack) {
+ if (!TextUtils.isEmpty(msg)) {
+ Logger.w(V2XConst.MODULE_NAME, "调用TTS播放语音:" + msg);
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice(msg, VoicePreemptType.PREEMPT_TYPE_IMMEADIATELY, callBack);
+ }
+ }
+
+ public IV2XWindow getV2XWindow() {
+ return mV2XWindow;
+ }
+
+ public void setV2XWindow(@Nullable IV2XWindow mV2XWindow) {
+ this.mV2XWindow = mV2XWindow;
+ }
+
+ public void setV2XButton(@Nullable IV2XButton mV2XButton) {
+ this.mV2XButton = mV2XButton;
+ }
+
+ public void setV2XMarker(@Nullable IV2XMarker mV2XMarker) {
+ this.mV2XMarker = mV2XMarker;
+ }
+
+ public void setV2XMessageEntity(@Nullable V2XMessageEntity mV2XMessageEntity) {
+ this.mV2XMessageEntity = mV2XMessageEntity;
+ }
+
+ public V2XMessageEntity getV2XMessageEntity() {
+ return mV2XMessageEntity;
+ }
+
+ @Override
+ public boolean isSameScenario(@Nullable V2XMessageEntity v2XMessageEntity) {
+ if (mV2XMessageEntity == null) {
+ return false;
+ }
+ return mV2XMessageEntity.equals(v2XMessageEntity);
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/V2XScenarioManager.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/V2XScenarioManager.java
new file mode 100644
index 0000000000..495fc47b96
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/impl/V2XScenarioManager.java
@@ -0,0 +1,111 @@
+package com.mogo.module.v2x.scenario.impl;
+
+import android.content.Intent;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.scenario.IV2XScenarioManager;
+import com.mogo.module.v2x.scenario.scene.animation.V2XAnimationScenario;
+import com.mogo.module.v2x.scenario.scene.fatigue.V2XFatigueDrivingScenario;
+import com.mogo.module.v2x.scenario.scene.help.V2XCarForHelpScenario;
+import com.mogo.module.v2x.scenario.scene.livecar.V2XPushLiveCarScenario;
+import com.mogo.module.v2x.scenario.scene.park.V2XIllegalParkScenario;
+import com.mogo.module.v2x.scenario.scene.push.V2XPushEventScenario;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventScenario;
+import com.mogo.module.v2x.scenario.scene.seek.V2XSeekHelpScenario;
+import com.mogo.module.v2x.utils.ToastUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.HashMap;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 4:22 PM
+ * desc : 场景管理的分发
+ * version: 1.0
+ */
+public class V2XScenarioManager implements IV2XScenarioManager {
+ private static V2XScenarioManager mV2XScenarioManager;
+ private AbsV2XScenario mV2XScenario;
+ private HashMap mV2XScenarioSet = new HashMap<>();
+
+ private V2XScenarioManager() {
+ }
+
+ public static V2XScenarioManager getInstance() {
+ if (mV2XScenarioManager == null) {
+ synchronized (V2XScenarioManager.class) {
+ if (mV2XScenarioManager == null) {
+ mV2XScenarioManager = new V2XScenarioManager();
+ }
+ }
+ }
+ return mV2XScenarioManager;
+ }
+
+ @Override
+ public void handlerMessage(V2XMessageEntity v2XMessageEntity) {
+ Logger.w(MODULE_NAME, "处理V2X场景:" + GsonUtil.jsonFromObject(v2XMessageEntity));
+ synchronized (V2XScenarioManager.class) {
+ // 展示
+ V2XUtils.runOnUiThread(() -> {
+ // 提取之前存储的场景
+ if (v2XMessageEntity != null) {
+ // 广播给应用内部其它模块
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(V2XUtils.getApp()).sendBroadcast(intent);
+
+ mV2XScenario = mV2XScenarioSet.get(v2XMessageEntity.getType());
+
+ // 如果没有拿到之前的,根据类型分发
+ if (mV2XScenario == null) {
+ switch (v2XMessageEntity.getType()) {
+ case V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING:
+ mV2XScenario = V2XRoadEventScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_SEEK_WARNING:
+ mV2XScenario = V2XSeekHelpScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_FATIGUE_DRIVING:
+ mV2XScenario = V2XFatigueDrivingScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_WINDOW_WARNING:
+ mV2XScenario = V2XPushEventScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_LIVE_CAR_WARNING:
+ mV2XScenario = V2XPushLiveCarScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_ANIMATION_WARNING:
+ mV2XScenario = V2XAnimationScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_CAR_FOR_HELP:
+ mV2XScenario = V2XCarForHelpScenario.getInstance();
+ break;
+ case V2XMessageEntity.V2XTypeEnum.ALERT_ILLEGAL_PARK_WARNING:
+ mV2XScenario = V2XIllegalParkScenario.getInstance();
+ break;
+ default:
+ ToastUtils.showLong("当前V2X消息类型未定义。");
+ return;
+ }
+ }
+
+
+ // 展示最新的消息
+ if (mV2XScenario != null) {
+ mV2XScenario.init(v2XMessageEntity);
+ mV2XScenarioSet.put(v2XMessageEntity.getType(), mV2XScenario);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationScenario.java
new file mode 100644
index 0000000000..bc55ad50a9
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationScenario.java
@@ -0,0 +1,121 @@
+package com.mogo.module.v2x.scenario.scene.animation;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.utils.logger.Logger;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 场景动画的场景展示,目前这里仅在演示DEMO中使用
+ * version: 1.0
+ */
+public class V2XAnimationScenario extends AbsV2XScenario {
+
+ private static V2XAnimationScenario mV2XAnimationScenario;
+
+ private V2XAnimationScenario() {
+ }
+
+
+ public static V2XAnimationScenario getInstance() {
+ if (mV2XAnimationScenario == null) {
+ synchronized (V2XAnimationScenario.class) {
+ if (mV2XAnimationScenario == null) {
+ mV2XAnimationScenario = new V2XAnimationScenario();
+ mV2XAnimationScenario.setV2XWindow(new V2XAnimationWindow());
+ }
+ }
+ }
+ return mV2XAnimationScenario;
+ }
+
+ @Override
+ public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
+ if (!isSameScenario(v2XMessageEntity)
+ && V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ boolean isV2XAnimationShow = V2XServiceManager.getMoGoV2XStatusManager().isV2XAnimationShow();
+ if (isV2XAnimationShow) {
+ close();
+ }
+ setV2XMessageEntity(v2XMessageEntity);
+ show();
+ } else {
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ }
+
+ @Override
+ public void show() {
+ showWindow();
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.setWindowStatusListener(new V2XWindowStatusListener() {
+ @Override
+ public void onViewShow() {
+ ADASUtils.broadcastToADAS(V2XServiceManager.getContext(), mV2XMessageEntity.getContent());
+ }
+
+ @Override
+ public void onViewClose() {
+ closeWindow();
+ clearPOI();
+ }
+ });
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ V2XServiceManager
+ .getIMogoWindowManager()
+ .addView(mV2XWindow.getView(), 0, 0, false);
+ V2XServiceManager.getMoGoV2XStatusManager().setV2XAnimationWindowShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setV2XAnimationWindowShow(TAG, false);
+ }
+
+ @Override
+ public void showButton() {
+ if (mV2XButton != null) {
+ mV2XButton.show();
+ }
+ }
+
+ @Override
+ public void closeButton() {
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ }
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ setV2XMessageEntity(null);
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationWindow.java
new file mode 100644
index 0000000000..0ece153745
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/animation/V2XAnimationWindow.java
@@ -0,0 +1,130 @@
+package com.mogo.module.v2x.scenario.scene.animation;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.view.TextureVideoView;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 11:34 AM
+ * desc : TODO 前瞻演示功能场景动画
+ * version: 1.0
+ */
+public class V2XAnimationWindow extends ConstraintLayout implements IV2XWindow {
+ // 弹窗状态监听
+ private V2XWindowStatusListener mV2XWindowStatusListener;
+ private TextureVideoView vvCarAnimation;
+
+ public V2XAnimationWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XAnimationWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XAnimationWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XAnimationWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ public void initView(Context context) {
+ Logger.w(MODULE_NAME, "初始化场景动画View。。。。。");
+ LayoutInflater.from(context).inflate(R.layout.window_animation, this);
+ vvCarAnimation = findViewById(R.id.vvCarAnimation);
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(V2XPushMessageEntity entity) {
+ Uri videoURI = null;
+ switch (entity.getSceneId()) {
+ // 前车紧急制动告警
+ case "100005":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_emergency_braking);
+ break;
+ // 十字路口碰撞预警
+ case "100006":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_left_right_car);
+ break;
+ // 岔路口碰撞预警
+ case "100007":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_cut_in_line);
+ break;
+ // 禁行车道预警
+ case "100008":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_current_row_closed);
+ break;
+ // 应急车辆优先通行
+ case "100012":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_emergency_lane);
+ break;
+ // 闯红灯预警
+ case "100013":
+ videoURI = Uri.parse("android.resource://" + getContext().getPackageName() + "/raw/" + R.raw.video_traffic_light_speed_cut);
+ break;
+ }
+
+ if (videoURI != null) {
+ vvCarAnimation.setVideoURI(videoURI);
+ vvCarAnimation.setOnPreparedListener(mediaPlayer -> {
+ Logger.w(MODULE_NAME, "场景动画准备。。。。。");
+ });
+ vvCarAnimation.setOnCompletionListener(mediaPlayer -> {
+ Logger.w(MODULE_NAME, "动画播放结束...");
+ if (mV2XWindowStatusListener != null) {
+ mV2XWindowStatusListener.onViewClose();
+ }
+ });
+ vvCarAnimation.start();
+ Logger.w(MODULE_NAME, "开始播放动画。。。。。");
+ }
+ }
+
+ @Override
+ public void close() {
+ //移除窗体
+ V2XServiceManager
+ .getIMogoWindowManager()
+ .removeView(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (vvCarAnimation != null) {
+ vvCarAnimation.stopPlayback();
+ }
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ this.mV2XWindowStatusListener = listener;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingScenario.java
new file mode 100644
index 0000000000..f529d85065
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingScenario.java
@@ -0,0 +1,157 @@
+package com.mogo.module.v2x.scenario.scene.fatigue;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 疲劳驾驶场景
+ * version: 1.0
+ */
+public class V2XFatigueDrivingScenario extends AbsV2XScenario implements IMogoTopViewStatusListener {
+
+ private static V2XFatigueDrivingScenario mV2XTiredScenario;
+ // 语音控制导航
+ private V2XVoiceCallbackListener mNaviCb = (command, intent) -> startNavi();
+
+ private V2XFatigueDrivingScenario() {
+ }
+
+ public static V2XFatigueDrivingScenario getInstance() {
+ if (mV2XTiredScenario == null) {
+ synchronized (V2XFatigueDrivingScenario.class) {
+ if (mV2XTiredScenario == null) {
+ mV2XTiredScenario = new V2XFatigueDrivingScenario();
+ mV2XTiredScenario.setV2XWindow(new V2XFatigueDrivingWindow());
+ }
+ }
+ }
+ return mV2XTiredScenario;
+ }
+
+ @Override
+ public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
+ if (!isSameScenario(v2XMessageEntity)) {
+ setV2XMessageEntity(v2XMessageEntity);
+ if (v2XMessageEntity != null) {
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI, mNaviCb)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP, mNaviCb);
+ if (v2XMessageEntity.isShowState()
+ && V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ show();
+ }
+ }
+ } else {
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ }
+
+ @Override
+ public void show() {
+ showWindow();
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp().getResources().getDimension(R.dimen.module_v2x_fatigue_driving_window_height_ground));
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addView(mV2XWindow.getView(), layoutParams, this);
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ V2XServiceManager.getMoGoV2XStatusManager().setFatigueDrivingWindowShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ }
+
+ @Override
+ public void showButton() {
+ }
+
+ @Override
+ public void closeButton() {
+ }
+
+ @Override
+ public void drawPOI() {
+ }
+
+ @Override
+ public void clearPOI() {
+ }
+
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ // 重置场景提示的消息
+ setV2XMessageEntity(null);
+ V2XServiceManager.getMoGoV2XStatusManager().setFatigueDrivingWindowShow(TAG, false);
+ }
+
+
+ /**
+ * 导航规划路线
+ */
+ private void startNavi() {
+ if (mV2XMessageEntity.getContent() != null) {
+ // 反注册语音交互
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP);
+ MogoLatLng endPoint = new MogoLatLng(mV2XMessageEntity.getContent().getLat(), mV2XMessageEntity.getContent().getLon());
+ V2XServiceManager.getNavi().naviTo(endPoint);
+ close();
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingWindow.java
new file mode 100644
index 0000000000..9ce5a57e2b
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/fatigue/V2XFatigueDrivingWindow.java
@@ -0,0 +1,195 @@
+package com.mogo.module.v2x.scenario.scene.fatigue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.navi.IMogoNaviListener;
+import com.mogo.map.navi.MogoNaviInfo;
+import com.mogo.map.navi.MogoTraffic;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.utils.SpanUtils;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 11:34 AM
+ * desc : 疲劳驾驶场景Window
+ * version: 1.0
+ */
+public class V2XFatigueDrivingWindow extends RelativeLayout
+ implements IV2XWindow, IMogoNaviListener {
+
+ private TextView mTvAddress, mTvAddressDistance;
+ private ImageView mIvToNav;
+
+ // 直播30秒自动关闭
+ private static Handler handlerV2XEvent = new Handler();
+ private static Runnable runnableV2XEvent;
+
+ // 推荐的停车场
+ private V2XPushMessageEntity mV2XPushMessageEntity;
+
+ public V2XFatigueDrivingWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XFatigueDrivingWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XFatigueDrivingWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XFatigueDrivingWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ public void initView(Context context) {
+ Logger.w(MODULE_NAME, "V2X-初始化疲劳驾驶");
+ LayoutInflater.from(context).inflate(R.layout.window_fatigue_driving, this);
+ mTvAddress = findViewById(R.id.tvAddress);
+ mTvAddressDistance = findViewById(R.id.tvAddressDistance);
+ mIvToNav = findViewById(R.id.ivToNav);
+ mIvToNav.setOnClickListener(v -> startNavi());
+ }
+
+ /**
+ * 导航规划路线
+ */
+ private void startNavi() {
+ if (mV2XPushMessageEntity != null) {
+ MogoLatLng endPoint = new MogoLatLng(mV2XPushMessageEntity.getLat(), mV2XPushMessageEntity.getLon());
+ V2XServiceManager.getNavi().naviTo(endPoint);
+ close();
+ }
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(V2XPushMessageEntity entity) {
+ mV2XPushMessageEntity = entity;
+ if (entity != null) {
+ if (!TextUtils.isEmpty(entity.getAddress())) {
+ mTvAddress.setText(entity.getAddress());
+ } else {
+ mTvAddress.setText("");
+ }
+ SpanUtils.with(mTvAddressDistance)
+ .append("" + (int) entity.getDistance())
+ .setFontSize(82)
+ .append("M")
+ .setFontSize(30)
+ .create();
+ countDownV2XEvent(entity);
+ }
+ }
+
+ @Override
+ public void close() {
+ // 反注册语音交互
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP);
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(this);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void countDownV2XEvent(V2XPushMessageEntity v2XPushMessageEntity) {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X=== Window 30秒倒计时结束。。。");
+ // 移出Window详细信息
+ close();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ int expireTime = v2XPushMessageEntity.getExpireTime();
+ Logger.d(MODULE_NAME, "V2X=== Window 展示开始倒计时:" + expireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, expireTime);
+ }
+
+
+ @Override
+ public void onCalculateSuccess() {
+ V2XServiceManager.getNavi().startNavi(true);
+ }
+
+ @Override
+ public void onInitNaviFailure() {
+
+ }
+
+ @Override
+ public void onInitNaviSuccess() {
+
+ }
+
+ @Override
+ public void onNaviInfoUpdate(MogoNaviInfo naviinfo) {
+
+ }
+
+ @Override
+ public void onStartNavi() {
+
+ }
+
+ @Override
+ public void onStopNavi() {
+
+ }
+
+ @Override
+ public void onoCalculateFailed() {
+
+ }
+
+ @Override
+ public void onUpdateTraffic(MogoTraffic traffic) {
+
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/help/V2XCarForHelpScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/help/V2XCarForHelpScenario.java
new file mode 100644
index 0000000000..3e0cda95a1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/help/V2XCarForHelpScenario.java
@@ -0,0 +1,232 @@
+package com.mogo.module.v2x.scenario.scene.help;
+
+import android.content.Intent;
+import android.os.CountDownTimer;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.scenario.scene.seek.V2XSeekHelpButton;
+import com.mogo.module.v2x.scenario.scene.seek.V2XSeekHelpDialog;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.entrance.ButtonIndex;
+import com.mogo.service.statusmanager.IMogoStatusChangedListener;
+import com.mogo.service.statusmanager.StatusDescriptor;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.storage.SharedPrefsMgr;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.scene
+ * @ClassName: V2XCarForHelpScenario
+ * @Description: 自车求助场景
+ * @Author: fenghl
+ * @CreateDate: 2020/5/25 11:44
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/25 11:44
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XCarForHelpScenario extends AbsV2XScenario implements IMogoStatusChangedListener {
+ private static final String TAG = MODULE_NAME + "_" + V2XCarForHelpScenario.class.getSimpleName();
+ private volatile static V2XCarForHelpScenario mV2XCarForHelpScenario;
+ private CountDownTimer mMySeekHelpCountDown;
+ private V2XSeekHelpDialog v2xFaultHelpDialog;
+
+ private V2XCarForHelpScenario() {
+ setV2XButton(new V2XSeekHelpButton());
+ V2XServiceManager.getMoGoStatusManager().registerStatusChangedListener(TAG, StatusDescriptor.SEEK_HELPING, this);
+ }
+
+ public static V2XCarForHelpScenario getInstance() {
+ if (mV2XCarForHelpScenario == null) {
+ synchronized (V2XCarForHelpScenario.class) {
+ if (mV2XCarForHelpScenario == null) {
+ mV2XCarForHelpScenario = new V2XCarForHelpScenario();
+ }
+ }
+ }
+ return mV2XCarForHelpScenario;
+ }
+
+ @Override
+ public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
+ // 设置Button的显示
+ if (v2XMessageEntity == null) {
+ return;
+ }
+ mV2XMessageEntity = v2XMessageEntity;
+ Boolean isShow = mV2XMessageEntity.getContent();
+ if (isShow) {
+ showButton();
+ mySeekHelpCountDownTimerCancel();
+ mySeekHelpCountDownTimerStart();
+ if (cancelCb == null) {
+ cancelCb = (String command, Intent intent) -> {
+ TextView tv = V2XServiceManager.getMogoEntranceButtonController().getButton(ButtonIndex.BUTTON2);
+ if (tv != null) {
+ showDialog();
+ }
+ };
+ }
+ unregisterSeekHelpButtonCmd();
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CANCEL_HELP, cancelCb);
+ V2XVoiceManager.INSTANCE.registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CANCEL_FOR_HELP_UN_WAKEUP, cancelCb);
+ } else {
+ closeButton();
+ }
+ }
+
+ @Override
+ public void show() {
+ showButton();
+ }
+
+ @Override
+ public void showWindow() {
+ //无window
+ }
+
+ @Override
+ public void closeWindow() {
+ //无window
+ }
+
+ private V2XVoiceCallbackListener cancelCb = null;
+
+ @Override
+ public void showButton() {
+ Logger.d(TAG, "打开自车求助按钮!");
+ // 设置Button的显示
+ V2XUtils.runOnUiThread(() -> {
+ if (mV2XButton != null) {
+ mV2XButton.setOnActionListener(this::showDialog);
+ mV2XButton.show();
+ }
+ });
+ }
+
+ @Override
+ public void closeButton() {
+ if (V2XServiceManager.getMoGoStatusManager().isSeekHelping()) {
+ Logger.d(TAG, "关闭自车求助按钮!");
+ V2XServiceManager.getMoGoStatusManager().setSeekHelping(TAG, false);
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ SharedPrefsMgr.getInstance(V2XUtils.getApp()).putLong(V2XConst.SEEK_HELP_TIME, 0);
+ }
+
+ mySeekHelpCountDownTimerCancel();
+ }
+ if (V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpPOIShow()) {
+ // 移除线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ // 移除事件POI
+ V2XServiceManager.getMoGoV2XMarkerManager().clearSpecialCarPOI();
+ // 绘制上次的数据
+ V2XServiceManager.getMoGoV2XMarkerManager().drawableLastAllPOI();
+ }
+
+
+ }
+
+
+ @Override
+ public void drawPOI() {
+ //无Poi
+ }
+
+ @Override
+ public void clearPOI() {
+ //无Poi
+ }
+
+
+ private void mySeekHelpCountDownTimerStart() {
+ long seekHelpTimeStart = SharedPrefsMgr.getInstance(V2XServiceManager.getContext()).getLong(V2XConst.SEEK_HELP_TIME, 0);
+ if (seekHelpTimeStart == 0) {
+ return;
+ }
+ long curTime = System.currentTimeMillis();
+ long timeOut = 10 * 60_000;
+ //超时时间
+ if (curTime - seekHelpTimeStart < timeOut) {
+ long min30 = 30 * 60 * 1000;
+ //long min30 = 10_000;
+ long countDown = seekHelpTimeStart + min30 - curTime;
+ //从自车故障时间起 30分钟后弹框提醒
+ if (mMySeekHelpCountDown == null) {
+ mMySeekHelpCountDown = new CountDownTimer(countDown, countDown) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+
+ }
+
+ @Override
+ public void onFinish() {
+ showDialog();
+ }
+ };
+ mMySeekHelpCountDown.start();
+ }
+ }
+ }
+
+ private void mySeekHelpCountDownTimerCancel() {
+ if (mMySeekHelpCountDown != null) {
+ mMySeekHelpCountDown.cancel();
+ mMySeekHelpCountDown = null;
+ }
+ }
+
+
+ public void showDialog() {
+ if (v2xFaultHelpDialog == null) {
+ v2xFaultHelpDialog = new V2XSeekHelpDialog(V2XServiceManager.getContext());
+ }
+ v2xFaultHelpDialog.setOnClickListener(new V2XSeekHelpDialog.OnClickListener() {
+ @Override
+ public void onClickLeft() {
+ //放弃求助
+ /* if (V2XServiceManager.getMoGoStatusManager().isSeekHelping()) {
+ V2XServiceManager.getMoGoStatusManager().setSeekHelping(TAG, false);
+ }*/
+ closeButton();
+ v2xFaultHelpDialog.dismiss();
+ }
+
+ @Override
+ public void onClickRight() {
+ //继续求助
+ v2xFaultHelpDialog.dismiss();
+
+ }
+ });
+ v2xFaultHelpDialog.show();
+
+ }
+
+ private void unregisterSeekHelpButtonCmd() {
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CANCEL_HELP);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CANCEL_FOR_HELP_UN_WAKEUP);
+ }
+
+ @Override
+ public void onStatusChanged(StatusDescriptor descriptor, boolean isTrue) {
+ if (descriptor == StatusDescriptor.SEEK_HELPING) {
+ V2XMessageEntity entity = new V2XMessageEntity<>();
+ entity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_CAR_FOR_HELP);
+ entity.setContent(isTrue);
+ init(entity);
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarScenario.java
new file mode 100644
index 0000000000..a11dffc26d
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarScenario.java
@@ -0,0 +1,151 @@
+package com.mogo.module.v2x.scenario.scene.livecar;
+
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.TipToast;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : TODO 演示使用的推送单车机直播场景
+ * version: 1.0
+ */
+public class V2XPushLiveCarScenario extends AbsV2XScenario implements IMogoTopViewStatusListener {
+
+ private static V2XPushLiveCarScenario mV2XLiveCarScenario;
+
+ private V2XPushLiveCarScenario() {
+ }
+
+ public static V2XPushLiveCarScenario getInstance() {
+ if (mV2XLiveCarScenario == null) {
+ synchronized (V2XPushLiveCarScenario.class) {
+ if (mV2XLiveCarScenario == null) {
+ mV2XLiveCarScenario = new V2XPushLiveCarScenario();
+ mV2XLiveCarScenario.setV2XWindow(new V2XPushLiveCarWindow());
+ }
+ }
+ }
+ return mV2XLiveCarScenario;
+ }
+
+ @Override
+ public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
+ if (!isSameScenario(v2XMessageEntity)
+ && V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ boolean isWindowShow = V2XServiceManager.getMoGoV2XStatusManager().isLeftLiveVideoShow();
+ if (isWindowShow) {
+ close();
+ }
+ setV2XMessageEntity(v2XMessageEntity);
+ if (v2XMessageEntity != null &&
+ (v2XMessageEntity.getContent().getVideoSn() != null ||
+ !TextUtils.isEmpty(v2XMessageEntity.getContent().getVideoUrl()))) {
+ show();
+ } else {
+ TipToast.shortTip("附近没有可直播车机");
+ Logger.e(V2XConst.MODULE_NAME, "直播地址为null");
+ }
+ } else {
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ }
+
+ @Override
+ public void show() {
+ showWindow();
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp().getResources().getDimension(R.dimen.module_v2x_event_window_height));
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addView(mV2XWindow.getView(), layoutParams, this);
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ V2XServiceManager.getMoGoV2XStatusManager().setLiveCarWindowShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setLiveCarWindowShow(TAG, false);
+ }
+
+ @Override
+ public void showButton() {
+ if (mV2XButton != null) {
+ mV2XButton.show();
+ }
+ }
+
+ @Override
+ public void closeButton() {
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ }
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ }
+
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ ADASUtils.broadcastToADAS(V2XServiceManager.getContext(), mV2XMessageEntity.getContent());
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ // 重置场景提示的消息
+ setV2XMessageEntity(null);
+ V2XServiceManager.getMoGoV2XStatusManager().setLiveCarWindowShow(TAG, false);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarWindow.java
new file mode 100644
index 0000000000..05edb72666
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XPushLiveCarWindow.java
@@ -0,0 +1,136 @@
+package com.mogo.module.v2x.scenario.scene.livecar;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import com.mogo.module.common.entity.MarkerCarInfo;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.module.v2x.view.V2XLiveGSYVideoView;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 11:34 AM
+ * desc : TODO 演示使用的推送单车机直播场景
+ * version: 1.0
+ */
+public class V2XPushLiveCarWindow extends RelativeLayout implements IV2XWindow {
+
+ private Context mContext;
+ private V2XLiveGSYVideoView mV2XLiveGSYVideoView;
+ // 弹窗状态监听
+ private V2XWindowStatusListener mV2XWindowStatusListener;
+
+ // 直播30秒自动关闭
+ private static Handler handlerV2XEvent = new Handler();
+ private static Runnable runnableV2XEvent;
+
+ public V2XPushLiveCarWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XPushLiveCarWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XPushLiveCarWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XPushLiveCarWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mContext = context;
+ initView(context);
+ }
+
+ public void initView(Context context) {
+ Logger.w(MODULE_NAME, "初始化直播小窗口View。。。。。");
+ LayoutInflater.from(context).inflate(R.layout.window_push_live_video, this);
+ // 详情列表
+ mV2XLiveGSYVideoView = findViewById(R.id.videoPlayer);
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(V2XPushMessageEntity entity) {
+ if (entity != null) {
+ Logger.w(MODULE_NAME, "更新直播信息。。。。。" + entity);
+
+ // 启动播放
+ MarkerCarInfo.CarLiveInfo carLiveInfo = new MarkerCarInfo.CarLiveInfo();
+ carLiveInfo.setVideoChannel(entity.getVideoChannel());
+ carLiveInfo.setVideoSn(entity.getVideoSn());
+ carLiveInfo.setVideoUrl(entity.getVideoUrl());
+ mV2XLiveGSYVideoView.startLive(carLiveInfo);
+ countDownV2XEvent(entity);
+
+ if (mV2XWindowStatusListener != null) {
+ mV2XWindowStatusListener.onViewShow();
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ // 修改地图比例
+ V2XServiceManager.getMoGoStatusManager().setUserInteractionStatus(MODULE_NAME, true, false);
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ // 如果窗体处于展示的时候
+ if (mV2XWindowStatusListener != null) {
+ mV2XWindowStatusListener.onViewClose();
+ }
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(this);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ this.mV2XWindowStatusListener = listener;
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void countDownV2XEvent(V2XPushMessageEntity v2XPushMessageEntity) {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X=== Window 30秒倒计时结束。。。");
+ // 移出Window详细信息
+ close();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ int expireTime = v2XPushMessageEntity.getExpireTime();
+ Logger.d(MODULE_NAME, "V2X=== Window 展示开始倒计时:" + expireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, expireTime);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarScenario.java
new file mode 100644
index 0000000000..ec0086f5bb
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarScenario.java
@@ -0,0 +1,153 @@
+package com.mogo.module.v2x.scenario.scene.livecar;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventScenario;
+import com.mogo.module.v2x.scenario.scene.road.V2XRoadEventWindow;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.logger.Logger;
+
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/29 11:16 AM
+ * desc : 道路预警中的直播场景
+ * version: 1.0
+ */
+public class V2XRoadLiveCarScenario extends AbsV2XScenario> implements IMogoTopViewStatusListener {
+ private static final String TAG = "V2XRoadEventScenario";
+ private static V2XRoadLiveCarScenario mV2XRoadLiveCarScenario;
+
+ private V2XRoadLiveCarScenario() {
+ }
+
+ public static V2XRoadLiveCarScenario getInstance() {
+ if (mV2XRoadLiveCarScenario == null) {
+ synchronized (V2XRoadLiveCarScenario.class) {
+ if (mV2XRoadLiveCarScenario == null) {
+ mV2XRoadLiveCarScenario = new V2XRoadLiveCarScenario();
+ }
+ }
+ }
+ return mV2XRoadLiveCarScenario;
+ }
+
+ @Override
+ public void init(V2XMessageEntity> v2XMessageEntity) {
+ try {
+ List v2XRoadEventEntity = v2XMessageEntity.getContent();
+ if (v2XRoadEventEntity != null) {
+ if (v2XMessageEntity.isShowState()) {
+ if (!isSameScenario(v2XMessageEntity)
+ && V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ mV2XRoadLiveCarScenario.setV2XWindow(new V2XRoadLiveCarWindow());
+ setV2XMessageEntity(v2XMessageEntity);
+ show();
+ } else {
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ } else {
+ close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void show() {
+ if (mV2XMessageEntity != null && mV2XMessageEntity.getContent() != null) {
+ showWindow();
+ }
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addSubView(mV2XWindow.getView(), this);
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadLiveCarWindowShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadLiveCarWindowShow(TAG, false);
+ }
+
+ @Override
+ public void showButton() {
+ if (mV2XButton != null) {
+ mV2XButton.show();
+ }
+ }
+
+ @Override
+ public void closeButton() {
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ }
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ }
+
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ // 警报状态,true-警报中,false-警报结束
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadLiveCarWindowShow(TAG, false);
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ // 打开直播后,窗口倒计时暂停关闭,直播被关闭后继续倒计时
+ V2XRoadEventWindow window = (V2XRoadEventWindow) V2XRoadEventScenario.getInstance().getV2XWindow();
+ window.startCountDown();
+ // 重置场景提示的消息
+ setV2XMessageEntity(null);
+ // 关闭场景提示
+ clearPOI();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarWindow.java
new file mode 100644
index 0000000000..9d9437b586
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/livecar/V2XRoadLiveCarWindow.java
@@ -0,0 +1,236 @@
+package com.mogo.module.v2x.scenario.scene.livecar;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.PagerSnapHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.adapter.V2XRoadEventAdapter;
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.module.v2x.voice.V2XVoicePagingListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 11:34 AM
+ * desc : 道路预警中的直播场景
+ * version: 1.0
+ */
+public class V2XRoadLiveCarWindow extends RelativeLayout
+ implements IV2XWindow> {
+ private String TAG = "V2XRoadEventDetailWindow";
+ private TextView mTvEventStubClose;
+ // 展示列表
+ private RecyclerView mRecyclerView;
+ // 列表数据适配器
+ private V2XRoadEventAdapter mV2XRoadEventAdapter;
+ // 列表展示
+ private List mItemList = new ArrayList<>();
+ // 当前展示的位置
+ private int mCurPosition;
+ // 处理道路事件,30秒倒计时
+ private Handler handlerV2XEvent = new Handler();
+ private Runnable runnableV2XEvent;
+ private int countDownTime = 30;
+ // 关闭弹窗回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackCloseWindowListener = (command, intent) -> close();
+ // 翻页回调监听
+ private V2XVoicePagingListener v2XVoicePagingCallbackListener = new V2XVoicePagingListener() {
+
+ @Override
+ public void onNextCallback() {
+ if (mRecyclerView != null && mCurPosition >= 0 && mCurPosition < mV2XRoadEventAdapter.getItemCount() - 1) {
+ mRecyclerView.scrollToPosition(mCurPosition + 1);
+ }
+ }
+
+ @Override
+ public void onPrevCallback() {
+ if (mRecyclerView != null && mCurPosition > 0 && mCurPosition <= mV2XRoadEventAdapter.getItemCount() - 1) {
+ mRecyclerView.scrollToPosition(mCurPosition - 1);
+ }
+ }
+ };
+
+ public V2XRoadLiveCarWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XRoadLiveCarWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XRoadLiveCarWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XRoadLiveCarWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ /**
+ * 初始化视图
+ */
+ private void initView(Context context) {
+ Logger.w(MODULE_NAME, "V2X===初始化道路直播视图");
+ // 填充布局
+ LayoutInflater.from(context).inflate(R.layout.window_road_live_car_detail, this);
+
+ mTvEventStubClose = findViewById(R.id.tvEventStubClose);
+ mRecyclerView = findViewById(R.id.rvRoadEventList);
+ mTvEventStubClose.setOnClickListener(v -> {
+ close();
+ });
+
+ mV2XRoadEventAdapter = new V2XRoadEventAdapter(mItemList);
+ mRecyclerView.setAdapter(mV2XRoadEventAdapter);
+ // 设置切换样式
+ new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+ // 配置列表朝向
+ LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
+ mRecyclerView.setLayoutManager(layoutManager);
+ mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (recyclerView.getChildCount() > 0) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ //获得当前显示在第一个item的位置
+ mCurPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
+ // 用户处于交互的时候延后隐藏时间
+ countDownV2XEvent(30000);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(List entity) {
+ Logger.d(MODULE_NAME, "V2X===道路事件直播:展示 Window :" + GsonUtil.jsonFromObject(entity));
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW,
+ v2XVoiceCallbackCloseWindowListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP,
+ v2XVoiceCallbackCloseWindowListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_LIVE_UN_WAKEUP,
+ v2XVoiceCallbackCloseWindowListener)
+ .registerPagingCallback(v2XVoicePagingCallbackListener);
+ // 更新头部的窗体视图
+ updateTopWindowInfo(entity);
+ // 倒计时
+ countDownV2XEvent(30000);
+ }
+
+ /**
+ * 更新头部的窗体视图
+ */
+ private void updateTopWindowInfo(List v2XRoadEventEntity) {
+ // 清空数据
+ mItemList.clear();
+ mItemList.addAll(v2XRoadEventEntity);
+ // 刷新列表
+ mV2XRoadEventAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * 关闭详情展示框
+ */
+ @Override
+ public void close() {
+ Logger.d(MODULE_NAME, "V2X===关闭Window");
+
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP);
+ V2XVoiceManager.INSTANCE.unRegisterPagingCallback();
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING)
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN)
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REPORT)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_TRUE)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_ERROR);
+
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+
+ if (V2XServiceManager
+ .getMogoTopViewManager().isViewAdded(this)) {
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeSubView(this);
+ }
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void countDownV2XEvent(int expireTime) {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X=== Window 30秒倒计时结束。。。");
+ // 移出Window详细信息
+ mTvEventStubClose.setText((countDownTime--) + "s");
+ handlerV2XEvent.postDelayed(runnableV2XEvent, 1000);
+ if (countDownTime <= 0) {
+ close();
+ }
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ Logger.d(MODULE_NAME, "V2X=== Window 展示开始倒计时:" + expireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, 1000);
+ }
+}
+
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkMarker.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkMarker.java
new file mode 100644
index 0000000000..2f30437784
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkMarker.java
@@ -0,0 +1,123 @@
+package com.mogo.module.v2x.scenario.scene.park;
+
+import android.os.Handler;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.anim.OnMarkerAnimationListener;
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.common.map.MapCenterPointStrategy;
+import com.mogo.module.common.map.Scene;
+import com.mogo.module.service.ServiceConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.scenario.view.IV2XMarker;
+import com.mogo.module.v2x.utils.MarkerUtils;
+import com.mogo.utils.WorkThreadHandler;
+import com.mogo.utils.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/6/19 17:37 PM
+ * desc : 违章停车场景POI绘制
+ * version: 1.0
+ */
+public class V2XIllegalParkMarker implements IV2XMarker> {
+
+ public ArrayList mIllegalParkMarkerList;
+
+ // 处理道路事件,30秒倒计时
+ private Handler handlerV2XEvent = new Handler();
+ private Runnable runnableV2XEvent;
+ private int mExpireTime = 30000;
+
+ @Override
+ public void drawPOI(List entityList) {
+ try {
+ mIllegalParkMarkerList = new ArrayList<>();
+ // 清除道路事件
+ V2XServiceManager
+ .getMoGoV2XMarkerManager().clearALLPOI();
+ if (entityList != null) {
+ for (int i = 0; i < entityList.size(); i++) {
+ MarkerExploreWay markerExploreWay = entityList.get(i);
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setBindObj(markerExploreWay);
+ markerShowEntity.setChecked(false);
+ markerShowEntity.setTextContent(markerExploreWay.getAddr());
+ markerShowEntity.setMarkerLocation(markerExploreWay.getLocation());
+ markerShowEntity.setMarkerType(ServiceConst.CARD_TYPE_NOVELTY);
+
+ WorkThreadHandler.getInstance().postDelayed(() -> {
+ IMogoMarker mogoMarker = V2XServiceManager.getIMogoMarkerService().drawMarker(markerShowEntity);
+ // 点击监听,天际弹窗展示详情
+ if (mogoMarker != null) {
+ mogoMarker.startScaleAnimation(0, 1.2f, 0, 1.2f, 300, new AccelerateInterpolator(), new OnMarkerAnimationListener() {
+ @Override
+ public void onAnimStart() {
+ Logger.d(MODULE_NAME, " onAnimStart ---1----> ");
+ }
+
+ @Override
+ public void onAnimEnd() {
+ if (mogoMarker.isDestroyed()) {
+ return;
+ }
+ mogoMarker.startScaleAnimation(1.2f, 1, 1.2f, 1, 100, new LinearInterpolator(), null);
+ }
+ });
+ mogoMarker.setOwner(MODULE_NAME);
+ mogoMarker.setObject(markerShowEntity);
+ mIllegalParkMarkerList.add(mogoMarker);
+ }
+ }, i * 100L);
+ }
+ }
+
+ countDownV2XEvent();
+ } catch (Exception e) {
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ // 移动回原来的中心点
+ MapCenterPointStrategy.setMapCenterPointByScene(V2XServiceManager.getMapUIController(), Scene.AIMLESS);
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ // 移除违章停车点
+ V2XServiceManager.getMarkerManager().removeMarkers(ServiceConst.CARD_TYPE_NOVELTY);
+ // 移除线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ // 移除事件POI
+ V2XServiceManager.getMoGoV2XMarkerManager().clearAlarmPOI();
+ }
+
+ /**
+ * 倒计时
+ */
+ public void countDownV2XEvent() {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X===违章停车 30秒倒计时结束。。。");
+ // 移出Window详细信息
+ clearPOI();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ Logger.d(MODULE_NAME, "V2X===违章停车 POI 展示开始倒计时:" + mExpireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, mExpireTime);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkScenario.java
new file mode 100644
index 0000000000..9bd5603dbe
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkScenario.java
@@ -0,0 +1,106 @@
+package com.mogo.module.v2x.scenario.scene.park;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.V2XStatusManager;
+import com.mogo.module.v2x.alarm.V2XAlarmServer;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.TrackUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 违章停车
+ * version: 1.0
+ */
+public class V2XIllegalParkScenario extends AbsV2XScenario> {
+ private static final String TAG = "V2XILLegalParkScenario";
+
+ private static V2XIllegalParkScenario mV2XIllegalParkScenario;
+
+ public static V2XIllegalParkScenario getInstance() {
+ if (mV2XIllegalParkScenario == null) {
+ synchronized (V2XIllegalParkScenario.class) {
+ if (mV2XIllegalParkScenario == null) {
+ mV2XIllegalParkScenario = new V2XIllegalParkScenario();
+ mV2XIllegalParkScenario.setV2XWindow(new V2XIllegalParkWindow());
+ mV2XIllegalParkScenario.setV2XMarker(new V2XIllegalParkMarker());
+ }
+ }
+ }
+ return mV2XIllegalParkScenario;
+ }
+
+ @Override
+ public void init(@Nullable V2XMessageEntity> v2XMessageEntity) {
+ setV2XMessageEntity(v2XMessageEntity);
+ show();
+ }
+
+
+ @Override
+ public void show() {
+ if (V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ drawPOI();
+ }
+ showWindow();
+ }
+
+ @Override
+ public void showWindow() {
+ MarkerExploreWay markerExploreWay = null;
+ if (mV2XMessageEntity.getContent() != null) {
+ markerExploreWay = V2XAlarmServer
+ .getIllegalParkAlarmEvent(
+ (ArrayList) mV2XMessageEntity.getContent(),
+ V2XStatusManager.getInstance().getLocation());
+ }
+ if (markerExploreWay != null) {
+ //弹框
+ // 设置要展开的违章停车事件
+ //((V2XIllegalParkMarker) mV2XMarker).setOpenPoiId(markerExploreWay.getInfoId());
+ if (V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ speakTTSVoice(markerExploreWay.getAddr() + "可能被罚违章停车,您可以说,有用或没用来帮助其它车友。", null);
+ ((V2XIllegalParkWindow) mV2XWindow).show(markerExploreWay, true);
+ TrackUtils.trackV2xRoadShow(markerExploreWay.getInfoId(), V2XPoiTypeEnum.ALERT_ILLEGAL_PARK, "1");
+ } else {
+ speakTTSVoice(markerExploreWay.getAddr() + "可能被罚违章停车", null);
+ TrackUtils.trackV2xRoadShow(markerExploreWay.getInfoId(), V2XPoiTypeEnum.ALERT_ILLEGAL_PARK, "2");
+ }
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ V2XServiceManager.getMogoTopViewManager().removeView(mV2XWindow.getView());
+ }
+
+ @Override
+ public void showButton() {
+ }
+
+ @Override
+ public void closeButton() {
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMessageEntity != null) {
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ }
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkWindow.java
new file mode 100644
index 0000000000..03e4b3a0c1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/park/V2XIllegalParkWindow.java
@@ -0,0 +1,209 @@
+package com.mogo.module.v2x.scenario.scene.park;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.utils.RoadConditionUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.view.HeartLikeView;
+import com.mogo.module.v2x.view.HeartUnLikeView;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.utils.logger.Logger;
+
+/**
+ * 违章停车
+ * 弹窗视图
+ */
+public class V2XIllegalParkWindow extends RelativeLayout implements IV2XWindow {
+ private static final String TAG = "V2XLegalParkWindow";
+
+ private TextView mAddressTv;
+ private TextView mIllegalNumTv;
+ private HeartLikeView mIlIllegalParkingLike;
+ private HeartUnLikeView mIIllegalParkingUnLike;
+
+ // 处理道路事件,20秒倒计时
+ private Handler handlerV2XEvent = new Handler();
+ private Runnable runnableV2XEvent;
+ private long mExpireTime = 20000;
+ private boolean mIsAutoClose = true;
+
+ private MarkerExploreWay mExploreWay;
+
+ // 反馈按钮语音操控
+ private V2XVoiceCallbackListener v2XVoiceCallbackYouYongListener = (command, intent) -> roadReportTrue();
+ private V2XVoiceCallbackListener v2XVoiceCallbackMeiYongListener = (command, intent) -> roadReportErr();
+
+ public V2XIllegalParkWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XIllegalParkWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XIllegalParkWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XIllegalParkWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ /**
+ * 初始化视图
+ */
+ private void initView(Context context) {
+ LayoutInflater.from(context).inflate(R.layout.window_illegal_parking, this);
+
+ mAddressTv = findViewById(R.id.tvAddress);
+ mIllegalNumTv = findViewById(R.id.tvIllegalNum);
+ mIlIllegalParkingLike = findViewById(R.id.llIllegalParkingLike);
+ mIIllegalParkingUnLike = findViewById(R.id.llIllegalParkingUnLike);
+ }
+
+ public void show(MarkerExploreWay entity, boolean isAutoClose) {
+ mIsAutoClose = isAutoClose;
+ show(entity);
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(MarkerExploreWay entity) {
+ mExploreWay = entity;
+ //Logger.d(V2XConst.MODULE_NAME, "V2X===违章停车:展示 Window=\n" + entity);
+ mAddressTv.setText(entity.getAddr());
+ try {
+ mIllegalNumTv.setText("违章人数:" + (int) entity.getItems().get(0).getIllegalCount());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ mIlIllegalParkingLike.setOnClickCallListener(v -> {
+ Logger.d(V2XConst.MODULE_NAME, "反馈有用");
+ roadReportTrue();
+ });
+
+ mIIllegalParkingUnLike.setOnClickCallListener(v -> {
+ Logger.d(V2XConst.MODULE_NAME, "反馈无用");
+ roadReportErr();
+ });
+
+ // 倒计时
+ if (mIsAutoClose) {
+ countDownV2XEvent();
+ }
+
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp()
+ .getResources()
+ .getDimension(R.dimen.module_v2x_fatigue_driving_window_height_ground));
+
+ // 添加弹窗
+ V2XServiceManager.getMogoTopViewManager().addView(this, layoutParams);
+
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ILLEGAL_PARKMARKER_FEEDBACK_YOUYONG_UN_WAKEUP,
+ v2XVoiceCallbackYouYongListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ILLEGAL_PARKMARKER_FEEDBACK_MEIYONG_UN_WAKEUP,
+ v2XVoiceCallbackMeiYongListener);
+
+ }
+
+ /**
+ * 关闭详情展示框
+ */
+ @Override
+ public void close() {
+ mIsAutoClose = false;
+
+ V2XVoiceManager.INSTANCE
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ILLEGAL_PARKMARKER_FEEDBACK_YOUYONG_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ILLEGAL_PARKMARKER_FEEDBACK_MEIYONG_UN_WAKEUP);
+
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(this);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void countDownV2XEvent() {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(V2XConst.MODULE_NAME, "V2X===20秒倒计时结束。。。");
+ // 移出Window详细信息
+ close();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ Logger.d(V2XConst.MODULE_NAME, "V2X===违章停车 Window 展示开始倒计时:" + mExpireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, mExpireTime);
+ }
+
+
+ /**
+ * 反馈路况正确
+ */
+ private void roadReportTrue() {
+ if (mExploreWay != null) {
+ RoadConditionUtils.sendDataErrorReceiverInfo(
+ mExploreWay.getPoiType(),
+ mExploreWay.getInfoId(),
+ "2");
+ }
+ close();
+ }
+
+ /**
+ * 反馈路况错误
+ */
+ private void roadReportErr() {
+ if (mExploreWay != null) {
+ RoadConditionUtils.sendDataErrorReceiverInfo(
+ mExploreWay.getPoiType(),
+ mExploreWay.getInfoId(),
+ "1");
+ }
+ close();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventMarker.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventMarker.java
new file mode 100644
index 0000000000..10e6fa9ac1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventMarker.java
@@ -0,0 +1,84 @@
+package com.mogo.module.v2x.scenario.scene.push;
+
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerExploreWayItem;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.map.MapCenterPointStrategy;
+import com.mogo.module.common.map.Scene;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.listener.V2XMarkerClickListener;
+import com.mogo.module.v2x.scenario.view.IV2XMarker;
+import com.mogo.module.v2x.utils.MarkerUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 推送场景
+ * version: 1.0
+ */
+public class V2XPushEventMarker implements IV2XMarker {
+ @Override
+ public void drawPOI(V2XPushMessageEntity entity) {
+ try {
+ // 清除道路事件
+ V2XServiceManager
+ .getMoGoV2XMarkerManager().clearALLPOI();
+
+ // 位置信息
+ MarkerLocation markerLocation = new MarkerLocation();
+ markerLocation.setLon(entity.getLon());
+ markerLocation.setLat(entity.getLat());
+
+ // 进行数据转换,用于Marker展示
+ V2XRoadEventEntity v2XRoadEventEntity = new V2XRoadEventEntity();
+ v2XRoadEventEntity.setLocation(markerLocation);
+ // 探路目前只有上报拥堵
+ v2XRoadEventEntity.setPoiType(V2XPoiTypeEnum.ALERT_TRAFFIC_EXPRESS);
+
+ MarkerExploreWay markerNoveltyInfo = new MarkerExploreWay();
+
+ List items = new ArrayList<>();
+ MarkerExploreWayItem exploreWayItem = new MarkerExploreWayItem();
+ exploreWayItem.setThumbnail(entity.getMsgImgUrl());
+ items.add(exploreWayItem);
+ markerNoveltyInfo.setPoiType(V2XPoiTypeEnum.ALERT_TRAFFIC_EXPRESS);
+ markerNoveltyInfo.setItems(items);
+ markerNoveltyInfo.setUploadType("1");
+
+ v2XRoadEventEntity.setNoveltyInfo(markerNoveltyInfo);
+ v2XRoadEventEntity.setExpireTime(20000);
+
+ V2XServiceManager
+ .getMoGoV2XMarkerManager()
+ .drawableAlarmPOI(V2XServiceManager.getContext(),
+ v2XRoadEventEntity,
+ V2XMarkerClickListener.getInstance());
+
+ } catch (Exception e) {
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ // 移动回原来的中心点
+ MapCenterPointStrategy.setMapCenterPointByScene(V2XServiceManager.getMapUIController(), Scene.AIMLESS);
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ // 移除线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ // 移除事件POI
+ V2XServiceManager.getMoGoV2XMarkerManager().clearAlarmPOI();
+ // 绘制上次的数据
+ V2XServiceManager.getMoGoV2XMarkerManager().drawableLastAllPOI();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventScenario.java
new file mode 100644
index 0000000000..85240f8983
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventScenario.java
@@ -0,0 +1,151 @@
+package com.mogo.module.v2x.scenario.scene.push;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 推送场景
+ * version: 1.0
+ */
+public class V2XPushEventScenario extends AbsV2XScenario implements IMogoTopViewStatusListener {
+
+ private static V2XPushEventScenario mV2XPushEventScenario;
+
+ private V2XPushEventScenario() {
+ }
+
+ public static V2XPushEventScenario getInstance() {
+ if (mV2XPushEventScenario == null) {
+ synchronized (V2XPushEventScenario.class) {
+ if (mV2XPushEventScenario == null) {
+ mV2XPushEventScenario = new V2XPushEventScenario();
+ mV2XPushEventScenario.setV2XMarker(new V2XPushEventMarker());
+ mV2XPushEventScenario.setV2XWindow(new V2XPushEventWindow());
+ }
+ }
+ }
+ return mV2XPushEventScenario;
+ }
+
+
+ @Override
+ public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
+ Logger.w(MODULE_NAME, "处理推送场景:" + GsonUtil.jsonFromObject(v2XMessageEntity));
+
+ if (!isSameScenario(v2XMessageEntity)
+ && V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ setV2XMessageEntity(v2XMessageEntity);
+ show();
+ } else {
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ }
+
+ @Override
+ public void show() {
+ if (mV2XMessageEntity != null && mV2XMessageEntity.getContent() != null) {
+ speakTTSVoice(mV2XMessageEntity.getContent().getTts(), null);
+ drawPOI();
+ showWindow();
+ }
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp().getResources().getDimension(R.dimen.module_v2x_event_window_height_ground));
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addView(mV2XWindow.getView(), layoutParams,this);
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ V2XServiceManager.getMoGoV2XStatusManager().setPushWindowShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeWindow() {
+ V2XServiceManager.getMoGoV2XStatusManager().setPushWindowShow(TAG, false);
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ }
+
+ @Override
+ public void showButton() {
+ if (mV2XButton != null) {
+ mV2XButton.show();
+ }
+ }
+
+ @Override
+ public void closeButton() {
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ }
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ V2XServiceManager.getMoGoV2XStatusManager().setPushPOIShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setPushPOIShow(TAG, false);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ V2XServiceManager.getMoGoV2XStatusManager().setPushWindowShow(TAG, false);
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ // 重置场景提示的消息
+ setV2XMessageEntity(null);
+ clearPOI();
+ }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventWindow.java
new file mode 100644
index 0000000000..352c225212
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/push/V2XPushEventWindow.java
@@ -0,0 +1,202 @@
+package com.mogo.module.v2x.scenario.scene.push;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.PagerSnapHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.adapter.V2XPushEventAdapter;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.utils.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/14 2:37 PM
+ * desc :
+ * TODO 目前睡前瞻推送使用的消息都在这里展示
+ * version: 1.0
+ */
+public class V2XPushEventWindow extends RelativeLayout implements IV2XWindow {
+ private String TAG = "V2XPushEventDetailWindow";
+ // 展示列表
+ private RecyclerView mRecyclerView;
+ // 列表数据适配器
+ private V2XPushEventAdapter mV2XRoadEventAdapter;
+ // 列表展示
+ private List mItemList = new ArrayList<>();
+ // 处理道路事件,30秒倒计时
+ private Handler handlerV2XEvent = new Handler();
+ private Runnable runnableV2XEvent;
+ private int mExpireTime = 30000;
+ // 关闭弹窗回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackCloseWindowListener = (String command, Intent intent) -> {
+ close();
+ };
+
+ public V2XPushEventWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XPushEventWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XPushEventWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XPushEventWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ /**
+ * 初始化视图
+ */
+ private void initView(Context context) {
+ Logger.w(MODULE_NAME, "V2X===初始化推送的消息小窗口View。。。。。");
+ // 填充布局
+ LayoutInflater.from(context).inflate(R.layout.window_push_event_detail, this);
+ // 详情列表
+ mRecyclerView = findViewById(R.id.rvRoadEventList);
+ mV2XRoadEventAdapter = new V2XPushEventAdapter(mItemList);
+ mRecyclerView.setAdapter(mV2XRoadEventAdapter);
+ // 设置切换样式
+ new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+ // 配置列表朝向
+ LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
+ mRecyclerView.setLayoutManager(layoutManager);
+ mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (recyclerView.getChildCount() > 0) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ // 用户处于交互的时候延后隐藏时间
+ countDownV2XEvent();
+ }
+ }
+ }
+ });
+
+ }
+
+ /**
+ * 更新头部的窗体视图
+ */
+ private void updateTopWindowInfo(V2XPushMessageEntity v2XRoadEventEntity) {
+ // 清空数据
+ mItemList.clear();
+ if (v2XRoadEventEntity != null) {
+ //Logger.d(MODULE_NAME, "V2X===推送消息:" + v2XRoadEventEntity);
+ mItemList.add(v2XRoadEventEntity);
+ }
+ // 刷新列表
+ mV2XRoadEventAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(V2XPushMessageEntity entity) {
+ Logger.d(MODULE_NAME, "V2X===推送消息:展示 Window=\n" + entity);
+ // 更新头部的窗体视图
+ updateTopWindowInfo(entity);
+ // 倒计时
+ mExpireTime = entity.getExpireTime();
+ countDownV2XEvent();
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW, v2XVoiceCallbackCloseWindowListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP, v2XVoiceCallbackCloseWindowListener);
+ }
+
+ /**
+ * 关闭详情展示框
+ */
+ @Override
+ public void close() {
+ Logger.d(MODULE_NAME, "V2X===关闭Window");
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP)
+ .unRegisterPagingCallback()
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING)
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN)
+ .unRegisterWakeCmd(
+ V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REPORT)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_TRUE)
+ .unRegisterUnWakeVoice(
+ V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_ERROR);
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(this);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void countDownV2XEvent() {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X===30秒倒计时结束。。。");
+ // 移出Window详细信息
+ close();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ Logger.d(MODULE_NAME, "V2X===推送消息 Window 展示开始倒计时:" + mExpireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, mExpireTime);
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventButton.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventButton.java
new file mode 100644
index 0000000000..7f195de836
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventButton.java
@@ -0,0 +1,83 @@
+package com.mogo.module.v2x.scenario.scene.road;
+
+import android.content.Intent;
+import android.view.View;
+import android.widget.TextView;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.scenario.view.IV2XButton;
+import com.mogo.module.v2x.scenario.view.IV2XButtonListener;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.entrance.ButtonIndex;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.view
+ * @ClassName: V2XRoadEventButton
+ * @Description: 道路实况按钮
+ * @Author: fenghl
+ * @CreateDate: 2020/5/18 10:46
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/18 10:46
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XRoadEventButton implements IV2XButton {
+ private TextView tv;
+ private IV2XButtonListener mListener;
+ private V2XVoiceCallbackListener mVoiceListener = (String command, Intent intent) -> {
+ if (mListener != null) {
+ mListener.onAction();
+ }
+ close();
+ };
+
+ @Override
+ public void setOnActionListener(IV2XButtonListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void show() {
+ // 注册语音交互
+ registerVoice();
+ tv = V2XServiceManager.getMogoEntranceButtonController().getButton(ButtonIndex.BUTTON1);
+ tv.setText("查看\n详情");
+ tv.setBackgroundResource(R.drawable.bg_v2x_event_live_show);
+ tv.setVisibility(View.VISIBLE);
+ tv.setOnClickListener(v -> {
+ if (mListener != null) {
+ mListener.onAction();
+ }
+ close();
+ });
+ }
+
+ @Override
+ public void close() {
+ if (tv != null) {
+ tv.setVisibility(View.GONE);
+ // 反注册语音交互
+ mListener = null;
+ }
+ unRegisterVoice();
+ }
+
+
+ @Override
+ public void registerVoice() {
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CONFIRM, mVoiceListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CONFIRM_UN_WAKEUP, mVoiceListener);
+ }
+
+ @Override
+ public void unRegisterVoice() {
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CONFIRM)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CONFIRM_UN_WAKEUP);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventMarker.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventMarker.java
new file mode 100644
index 0000000000..b3da065410
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventMarker.java
@@ -0,0 +1,53 @@
+package com.mogo.module.v2x.scenario.scene.road;
+
+import com.mogo.module.common.map.MapCenterPointStrategy;
+import com.mogo.module.common.map.Scene;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.scenario.view.IV2XMarker;
+import com.mogo.module.v2x.utils.MarkerUtils;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.view
+ * @ClassName: V2XRoadEventMarker
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/5/18 10:48
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/18 10:48
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XRoadEventMarker implements IV2XMarker {
+ @Override
+ public void drawPOI(V2XRoadEventEntity entity) {
+ try {
+ // 清除道路事件
+ V2XServiceManager
+ .getMoGoV2XMarkerManager().clearALLPOI();
+ if (entity != null) {
+ V2XServiceManager.getMoGoV2XMarkerManager()
+ .drawableAlarmPOI(V2XServiceManager.getContext(), entity, null);
+ }
+ } catch (Exception e) {
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ // 移动回原来的中心点
+ MapCenterPointStrategy.setMapCenterPointByScene(V2XServiceManager.getMapUIController(), Scene.AIMLESS);
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ // 移除线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ // 移除事件POI
+ V2XServiceManager.getMoGoV2XMarkerManager().clearAlarmPOI();
+ // 绘制上次的数据
+ V2XServiceManager.getMoGoV2XMarkerManager().drawableLastAllPOI();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventScenario.java
new file mode 100644
index 0000000000..e69073c022
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventScenario.java
@@ -0,0 +1,212 @@
+package com.mogo.module.v2x.scenario.scene.road;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.scenario.scene.livecar.V2XRoadLiveCarScenario;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 道路预警场景
+ * version: 1.0
+ */
+public class V2XRoadEventScenario extends AbsV2XScenario implements IMogoTopViewStatusListener {
+ private static final String TAG = "V2XRoadEventScenario";
+ private static V2XRoadEventScenario mV2XRoadEventScenario;
+
+ private V2XRoadEventScenario() {
+ }
+
+ public static V2XRoadEventScenario getInstance() {
+ if (mV2XRoadEventScenario == null) {
+ synchronized (V2XRoadEventScenario.class) {
+ if (mV2XRoadEventScenario == null) {
+ mV2XRoadEventScenario = new V2XRoadEventScenario();
+ mV2XRoadEventScenario.setV2XButton(new V2XRoadEventButton());
+ mV2XRoadEventScenario.setV2XMarker(new V2XRoadEventMarker());
+ mV2XRoadEventScenario.setV2XWindow(new V2XRoadEventWindow());
+ }
+ }
+ }
+ return mV2XRoadEventScenario;
+ }
+
+ @Override
+ public void init(V2XMessageEntity v2XMessageEntity) {
+ try {
+ Logger.w(V2XConst.MODULE_NAME, "v2XMessageEntity:" + GsonUtil.jsonFromObject(v2XMessageEntity));
+
+ V2XRoadEventEntity v2XRoadEventEntity = v2XMessageEntity.getContent();
+ if (v2XRoadEventEntity != null) {
+ if (v2XMessageEntity.isShowState()) {
+ if (!isSameScenario(v2XMessageEntity)) {
+ // 更新要提醒的数据
+ setV2XMessageEntity(v2XMessageEntity);
+ show();
+ } else {
+ // 更新要提醒的数据
+ setV2XMessageEntity(v2XMessageEntity);
+ Logger.w(V2XConst.MODULE_NAME, "要处理的场景已经存在,丢弃这次初始化");
+ }
+ } else {
+ close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void show() {
+ if (mV2XMessageEntity != null && mV2XMessageEntity.getContent() != null) {
+ // 如果道路事件小于50米的时候需要用户反馈
+ if (mV2XMessageEntity.getContent().getDistance() < 50) {
+ // 设置TTS
+ mV2XMessageEntity.getContent().getTtsWithFeedback();
+ } else {
+ // 设置TTS
+ mV2XMessageEntity.getContent().getTts(false);
+ }
+ // 广播给ADAS
+ ADASUtils.broadcastToADAS(
+ V2XServiceManager.getContext(),
+ mV2XMessageEntity.getContent());
+ if (V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ drawPOI();
+ showWindow();
+ }
+ }
+ }
+
+ @Override
+ public void showWindow() {
+ if (mV2XWindow != null) {
+ // 关闭直播弹窗
+ try {
+ IV2XWindow v2XWindow = V2XRoadLiveCarScenario.getInstance().getV2XWindow();
+ if (v2XWindow != null) {
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeSubView(v2XWindow.getView());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // 关闭之前的事件弹窗
+ boolean isShowEventWindow = V2XServiceManager.getMoGoV2XStatusManager().isRoadEventWindowShow();
+ if (isShowEventWindow) {
+ ((V2XRoadEventWindow) mV2XWindow).updateTopWindowInfo(mV2XMessageEntity.getContent());
+ } else {
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp().getResources().getDimension(R.dimen.module_v2x_event_window_height));
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addView(mV2XWindow.getView(), layoutParams, this);
+ mV2XWindow.show(mV2XMessageEntity.getContent());
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventWindowShow(TAG, true);
+ }
+
+ // 地图主动推送/触发消息 埋点
+ String poiType = mV2XMessageEntity.getContent().getPoiType();
+ String lat = String.valueOf(mV2XMessageEntity.getContent().getLocation().getLat());
+ String lon = String.valueOf(mV2XMessageEntity.getContent().getLocation().getLon());
+ String infoId = mV2XMessageEntity.getContent().getNoveltyInfo().getInfoId();
+ String style = V2XServiceManager.getMoGoStatusManager().isMainPageOnResume() ? "1" : "2";
+ Map properties = new HashMap<>();
+ properties.put("dbid", infoId);
+ properties.put("type", poiType);
+ properties.put("lng", lon);
+ properties.put("lat", lat);
+ properties.put("style", style);
+ V2XServiceManager.getMogoAnalytics().track(V2XConst.V2X_ROAD_SHOW, properties);
+ }
+
+ @Override
+ public void closeWindow() {
+ if (mV2XWindow != null) {
+ mV2XWindow.close();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventWindowShow(TAG, false);
+ }
+
+ @Override
+ public void showButton() {
+ if (mV2XButton != null) {
+ mV2XButton.setOnActionListener(this::showWindow);
+ mV2XButton.show();
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventButtonShow(TAG, true);
+ }
+ }
+
+ @Override
+ public void closeButton() {
+ if (mV2XButton != null) {
+ mV2XButton.close();
+ }
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventButtonShow(TAG, false);
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null) {
+ // 重置告警信息
+ V2XServiceManager.getV2XStatusManager().setAlarmInfo(mV2XMessageEntity.getContent());
+ mV2XMarker.drawPOI(mV2XMessageEntity.getContent());
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ }
+
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ V2XServiceManager.getMoGoV2XStatusManager().setRoadEventWindowShow(TAG, false);
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ // 重置场景提示的消息
+ setV2XMessageEntity(null);
+ clearPOI();
+ closeButton();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventWindow.java
new file mode 100644
index 0000000000..8723cb1dd9
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/road/V2XRoadEventWindow.java
@@ -0,0 +1,285 @@
+package com.mogo.module.v2x.scenario.scene.road;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.PagerSnapHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.adapter.V2XRoadEventAdapter;
+import com.mogo.module.common.entity.V2XEventShowEntity;
+import com.mogo.module.v2x.entity.net.V2XLiveCarRes;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.common.entity.V2XWindowTypeEnum;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.module.v2x.voice.V2XVoicePagingListener;
+import com.mogo.utils.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/14 2:37 PM
+ * desc : 显示事件的列表
+ * version: 1.0
+ */
+public class V2XRoadEventWindow extends RelativeLayout
+ implements V2XRefreshCallback, IV2XWindow {
+ private String TAG = "V2XRoadEventDetailWindow";
+ // 展示列表
+ private RecyclerView mRecyclerView;
+ // 列表数据适配器
+ private V2XRoadEventAdapter mV2XRoadEventAdapter;
+ // 列表展示
+ private List mItemList = new ArrayList<>();
+ // 当前展示的位置
+ private int mCurPosition;
+ // 处理道路事件,30秒倒计时
+ private Handler handlerV2XEvent = new Handler();
+ private Runnable runnableV2XEvent;
+ private int mExpireTime = 20000;
+ // 关闭弹窗回调
+ private V2XVoiceCallbackListener v2XVoiceCallbackCloseWindowListener = (command, intent) -> close();
+ // 翻页回调监听
+ private V2XVoicePagingListener v2XVoicePagingCallbackListener = new V2XVoicePagingListener() {
+
+ @Override
+ public void onNextCallback() {
+ if (mRecyclerView != null && mCurPosition >= 0 && mCurPosition < mV2XRoadEventAdapter.getItemCount() - 1) {
+ mRecyclerView.scrollToPosition(mCurPosition + 1);
+ }
+ }
+
+ @Override
+ public void onPrevCallback() {
+ if (mRecyclerView != null && mCurPosition > 0 && mCurPosition <= mV2XRoadEventAdapter.getItemCount() - 1) {
+ mRecyclerView.scrollToPosition(mCurPosition - 1);
+ }
+ }
+ };
+
+ public V2XRoadEventWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+
+ public V2XRoadEventWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XRoadEventWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XRoadEventWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ /**
+ * 初始化视图
+ */
+ private void initView(Context context) {
+ Logger.w(MODULE_NAME, "V2X===初始化道路事件小窗口View。。。。。");
+ // 填充布局
+ LayoutInflater.from(context).inflate(R.layout.window_road_event_detail, this);
+ // 详情列表
+ mRecyclerView = findViewById(R.id.rvRoadEventList);
+ mV2XRoadEventAdapter = new V2XRoadEventAdapter(mItemList);
+ mRecyclerView.setAdapter(mV2XRoadEventAdapter);
+ // 设置切换样式
+ new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+ // 配置列表朝向
+ LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
+ mRecyclerView.setLayoutManager(layoutManager);
+ mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (recyclerView.getChildCount() > 0) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ //获得当前显示在第一个item的位置
+ mCurPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
+ // 用户处于交互的时候延后隐藏时间
+ startCountDown();
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 展示道路事件详情Windows
+ */
+ @Override
+ public void show(V2XRoadEventEntity entity) {
+ //Logger.d(MODULE_NAME, "V2X===道路事件详情:展示 Window:" + entity);
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE
+ .registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW, v2XVoiceCallbackCloseWindowListener)
+ .registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP, v2XVoiceCallbackCloseWindowListener)
+ .registerPagingCallback(v2XVoicePagingCallbackListener);
+ // 更新头部的窗体视图
+ updateTopWindowInfo(entity);
+
+ // 倒计时
+ mExpireTime = entity.getExpireTime();
+ startCountDown();
+ }
+
+ /**
+ * 更新头部的窗体视图
+ */
+ public void updateTopWindowInfo(V2XRoadEventEntity v2XRoadEventEntity) {
+ Logger.d(MODULE_NAME, "V2X===道路事件详情:更新 Window:" + v2XRoadEventEntity);
+
+ // 清空数据
+ mItemList.clear();
+ if (v2XRoadEventEntity != null) {
+ // 道路事件行驶到了50米附近,弹出事件纠错框给用户
+ //Logger.d(MODULE_NAME, "V2X===道路事件:" + v2XRoadEventEntity);
+ // 进行类型分发
+ switch (v2XRoadEventEntity.getPoiType()) {
+ case V2XPoiTypeEnum.TRAFFIC_CHECK: // 交通检查
+ case V2XPoiTypeEnum.ROAD_CLOSED://封路
+ case V2XPoiTypeEnum.FOURS_ROAD_WORK://施工
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP://拥堵
+ case V2XPoiTypeEnum.FOURS_PONDING://积水
+ case V2XPoiTypeEnum.FOURS_FOG://浓雾
+ case V2XPoiTypeEnum.FOURS_ICE://结冰
+ case V2XPoiTypeEnum.FOURS_ACCIDENT://事故
+ // 展示道路事件本身详情
+ if (mItemList.isEmpty()) {
+ V2XEventShowEntity v2XEventShowEntity = new V2XEventShowEntity();
+ v2XEventShowEntity.setViewType(V2XWindowTypeEnum.ROAD_EVENT_WINDOW);
+ v2XEventShowEntity.setV2XRoadEventEntity(v2XRoadEventEntity);
+ mItemList.add(v2XEventShowEntity);
+ }
+ // 获取道路事件周边的直播车机
+ V2XServiceManager
+ .getV2XRefreshModel()
+ .queryNearbyVehicleLiveByLocation(
+ this,
+ v2XRoadEventEntity.getLocation().getLon(),
+ v2XRoadEventEntity.getLocation().getLat());
+ break;
+ }
+ }
+ // 刷新列表
+ mV2XRoadEventAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onSuccess(V2XLiveCarRes result) {
+ // TODO 这里是测试数据
+ //result = TestOnLineCarUtils.queryNearbyVehicleLiveByLocation();
+ //Logger.d(MODULE_NAME, "V2X===事件周边的直播车机:" + result);
+ try {
+ if (!mItemList.isEmpty() &&
+ result != null &&
+ result.getResult() != null &&
+ result.getResult().getInfo() != null &&
+ result.getResult().getInfo().size() > 0) {
+ mItemList.get(0).setV2XLiveCarList(result.getResult().getInfo());
+ }
+ // 刷新列表
+ mV2XRoadEventAdapter.notifyDataSetChanged();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onFail(String msg) {
+
+ }
+
+
+ /**
+ * 关闭详情展示框
+ */
+ @Override
+ public void close() {
+ Logger.d(MODULE_NAME, "V2X===关闭 Window");
+ // 注册语音交互
+ V2XVoiceManager.INSTANCE.unRegisterPagingCallback();
+ V2XVoiceManager.INSTANCE
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CLOSE_WINDOW)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CLOSE_WINDOW_UN_WAKEUP)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_ZAN)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REPORT)
+ .unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_LIVE_ROAD)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_OPEN_LIVE_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_ZAN_UN_WAKEUP)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_TRUE)
+ .unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_FEEDBACK_ERROR);
+
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+
+ //移除窗体
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(this);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ }
+
+ /**
+ * 窗体倒计时
+ */
+ public void startCountDown() {
+ // 倒计时
+ if (runnableV2XEvent == null) {
+ runnableV2XEvent = () -> {
+ Logger.d(MODULE_NAME, "V2X=== Window 30秒倒计时结束。。。");
+ // 移出Window详细信息
+ close();
+ };
+ } else {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ }
+ Logger.d(MODULE_NAME, "V2X=== Window 展示开始倒计时:" + mExpireTime);
+ handlerV2XEvent.postDelayed(runnableV2XEvent, mExpireTime);
+ }
+
+ /**
+ * 停止倒计时
+ */
+ public void stopCountDown() {
+ // 停止倒计时
+ if (handlerV2XEvent != null && runnableV2XEvent != null) {
+ handlerV2XEvent.removeCallbacks(runnableV2XEvent);
+ runnableV2XEvent = null;
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpButton.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpButton.java
new file mode 100644
index 0000000000..84d9191d17
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpButton.java
@@ -0,0 +1,93 @@
+package com.mogo.module.v2x.scenario.scene.seek;
+
+import android.content.Intent;
+import android.view.View;
+import android.widget.TextView;
+
+import com.mogo.commons.data.BaseData;
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.network.V2XRefreshCallback;
+import com.mogo.module.v2x.scenario.view.IV2XButton;
+import com.mogo.module.v2x.scenario.view.IV2XButtonListener;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.entrance.ButtonIndex;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.view
+ * @ClassName: V2XSeekHelpButton
+ * @Description: 自车求助按钮
+ * @Author: fenghl
+ * @CreateDate: 2020/5/18 10:46
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/18 10:46
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XSeekHelpButton implements IV2XButton {
+ private TextView tv;
+ private IV2XButtonListener mListener;
+ private V2XVoiceCallbackListener cancelCb = (String command, Intent intent) -> {
+ doAction();
+ };
+
+ private void doAction() {
+ if (mListener != null) {
+ mListener.onAction();
+ }
+ }
+
+ @Override
+ public void setOnActionListener(IV2XButtonListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void show() {
+ registerVoice();
+ tv = V2XServiceManager.getMogoEntranceButtonController().getButton(ButtonIndex.BUTTON2);
+ tv.setText("取消\n求助");
+ tv.setVisibility(View.VISIBLE);
+ tv.setBackgroundResource(R.drawable.bg_v2x_event_live_show);
+ tv.setOnClickListener(v -> {
+ //调用取消求助接口
+ // TODO: 2020/5/18 回调,显示对话框
+ doAction();
+ });
+ }
+
+ @Override
+ public void close() {
+ if (tv != null) {
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("将为您取消", null);
+ tv.setVisibility(View.GONE);
+ V2XServiceManager
+ .getV2XRefreshModel().cancelHelpSignal(new V2XRefreshCallback() {
+ @Override
+ public void onSuccess(BaseData result) {
+ tv.setVisibility(View.GONE);
+ }
+ @Override
+ public void onFail(String msg) {
+ tv.setVisibility(View.VISIBLE);
+ }
+ });
+ mListener = null;
+ }
+ unRegisterVoice();
+ }
+ @Override
+ public void registerVoice() {
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CANCEL_HELP, cancelCb);
+ }
+
+ @Override
+ public void unRegisterVoice() {
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CANCEL_HELP);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpDialog.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpDialog.java
new file mode 100644
index 0000000000..d1ae3f2d22
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpDialog.java
@@ -0,0 +1,176 @@
+package com.mogo.module.v2x.scenario.scene.seek;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.utils.WindowUtils;
+import com.mogo.utils.logger.Logger;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.window
+ * @ClassName: V2XDialog
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/4/22 14:27
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/4/22 14:27
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XSeekHelpDialog extends ConstraintLayout implements View.OnClickListener {
+ public static final String TAG = "V2XDialog";
+ private TextView tvContent;
+ private TextView tvLeft;
+ private TextView tvRight;
+ private Context mContext;
+
+ public V2XSeekHelpDialog(Context context) {
+ this(context, null);
+ }
+
+ public V2XSeekHelpDialog(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XSeekHelpDialog(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ init(context);
+ }
+
+ private void init(Context context) {
+ mContext = context;
+ LayoutInflater.from(context).inflate(R.layout.dialog_v2x_common, this);
+ tvContent = findViewById(R.id.tvDialogContent);
+ tvLeft = findViewById(R.id.tvDialogLeft);
+ tvRight = findViewById(R.id.tvDialogRight);
+ tvContent.setText("确定解除求助状态?");
+ tvLeft.setText("确定");
+ tvRight.setText("取消");
+ tvLeft.setOnClickListener(this);
+ tvRight.setOnClickListener(this);
+
+ }
+
+ private OnClickListener mListener;
+
+ public void setOnClickListener(OnClickListener listener) {
+ mListener = listener;
+ }
+
+ public interface OnClickListener {
+ void onClickLeft();
+
+ void onClickRight();
+ }
+
+ boolean isShown;
+ WindowManager windowManager;
+
+ public void show() {
+ Logger.d(TAG, "使用windowManager实现");
+ if (!isShown) {
+ windowManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ } else {
+ layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+ }
+ layoutParams.format = PixelFormat.TRANSLUCENT;
+ layoutParams.gravity = Gravity.START | Gravity.TOP;
+// mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ // FLAG_LAYOUT_IN_SCREEN:将window放置在整个屏幕之内,无视其他的装饰(比如状态栏); FLAG_NOT_TOUCH_MODAL:不阻塞事件传递到后面的窗口
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.width = WindowUtils.getScreenWidth(mContext);
+ layoutParams.height = WindowUtils.getScreenHeight(mContext);
+ //后面变暗区域透明...
+ layoutParams.dimAmount = 0;
+ layoutParams.x = 0;
+ layoutParams.y = 0;
+ windowManager.addView(this, layoutParams);
+ isShown = true;
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("确定要解除求助状态吗");
+ unRegisterVoiceCmd();
+ registerVoiceCmd();
+ }
+ }
+
+ private V2XVoiceCallbackListener voiceRightCb = (String command, Intent intent) -> {
+ //继续求助
+ handleRight();
+ };
+ private V2XVoiceCallbackListener voiceLeftCb = (String command, Intent intent) -> {
+
+ //放弃求助
+ handleLeft();
+ };
+
+ public void dismiss() {
+ if (isShown && windowManager != null) {
+ windowManager.removeViewImmediate(this);
+ windowManager = null;
+ isShown = false;
+ }
+ }
+
+
+ //放弃求助
+ private void handleLeft() {
+ if (mListener != null) {
+ mListener.onClickLeft();
+ }
+
+ unRegisterVoiceCmd();
+ }
+
+ //继续求助
+ private void handleRight() {
+ if (mListener != null) {
+ mListener.onClickRight();
+ }
+ unRegisterVoiceCmd();
+
+ }
+
+ private void registerVoiceCmd() {
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CONFIRM, voiceLeftCb);
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CANCEL, voiceRightCb);
+ V2XVoiceManager.INSTANCE.registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CONFIRM_UN_WAKEUP, voiceLeftCb);
+ V2XVoiceManager.INSTANCE.registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CANCEL_UN_WAKEUP, voiceRightCb);
+ }
+
+ private void unRegisterVoiceCmd() {
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CONFIRM);
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_COMMON_CANCEL);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CONFIRM_UN_WAKEUP);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CANCEL_UN_WAKEUP);
+ }
+
+ @Override
+ public void onClick(View v) {
+ int vId = v.getId();
+ if (vId == R.id.tvDialogLeft) {
+ handleLeft();
+ } else if (vId == R.id.tvDialogRight) {
+ handleRight();
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpMarker.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpMarker.java
new file mode 100644
index 0000000000..7ccbf06cfa
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpMarker.java
@@ -0,0 +1,54 @@
+package com.mogo.module.v2x.scenario.scene.seek;
+
+import android.content.Context;
+
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.v2x.listener.V2XMarkerClickListener;
+import com.mogo.module.v2x.scenario.view.IV2XMarker;
+import com.mogo.module.v2x.utils.MarkerUtils;
+
+import java.util.List;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.view
+ * @ClassName: V2XSeekHelpMarker
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/5/18 10:48
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/18 10:48
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XSeekHelpMarker implements IV2XMarker> {
+
+ @Override
+ public void drawPOI(List entity) {
+ // 移除上一次的数据
+ Context context = V2XServiceManager.getContext();
+ for (V2XMarkerEntity coordinate : entity) {
+ //故障车机
+ if (coordinate.getTargetId() == V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING) {
+ //绘制
+ V2XServiceManager
+ .getMoGoV2XMarkerManager()
+ .drawableSpecialCarPOI(context, coordinate, V2XMarkerClickListener.getInstance());
+ }
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ MarkerUtils.resetMapZoom(16);
+ // 移除线
+ V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
+ // 移除事件POI
+ V2XServiceManager.getMoGoV2XMarkerManager().clearSpecialCarPOI();
+ // 绘制上次的数据
+ V2XServiceManager.getMoGoV2XMarkerManager().drawableLastAllPOI();
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpScenario.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpScenario.java
new file mode 100644
index 0000000000..a014a47eac
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpScenario.java
@@ -0,0 +1,217 @@
+package com.mogo.module.v2x.scenario.scene.seek;
+
+import android.os.CountDownTimer;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.scenario.impl.AbsV2XScenario;
+import com.mogo.module.v2x.utils.ADASUtils;
+import com.mogo.module.v2x.utils.V2XUtils;
+import com.mogo.service.windowview.IMogoTopViewStatusListener;
+import com.mogo.utils.logger.Logger;
+
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:37 PM
+ * desc : 故障求助场景
+ * version: 1.0
+ */
+public class V2XSeekHelpScenario extends AbsV2XScenario> implements IMogoTopViewStatusListener {
+ private volatile static V2XSeekHelpScenario mV2XSeekHelpScenario;
+
+ private V2XSeekHelpScenario() {
+ }
+
+ public static V2XSeekHelpScenario getInstance() {
+ if (mV2XSeekHelpScenario == null) {
+ synchronized (V2XSeekHelpScenario.class) {
+ if (mV2XSeekHelpScenario == null) {
+ mV2XSeekHelpScenario = new V2XSeekHelpScenario();
+ }
+ }
+ }
+ return mV2XSeekHelpScenario;
+ }
+
+ private List mMarkerEntity;
+
+ @Override
+ public void init(@Nullable V2XMessageEntity> v2XMessageEntity) {
+ mV2XMessageEntity = v2XMessageEntity;
+ if (V2XServiceManager.getMoGoStatusManager().isMainPageLaunched()) {
+ if (mV2XMessageEntity != null) {
+ mMarkerEntity = mV2XMessageEntity.getContent();
+ }
+ if (!isShown) {
+ setV2XWindow(new V2XSeekHelpWindow());
+ setV2XMarker(new V2XSeekHelpMarker());
+ } else {
+ countDownFaultHelpWindowCancel();
+ closeWindow();
+ clearPOI();
+ }
+ show();
+ }
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("发现其他车主的求助信息");
+ // 广播给ADAS和Launcher卡片
+ V2XRoadEventEntity eventEntity = new V2XRoadEventEntity();
+ eventEntity.setPoiType(V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING + "");
+ eventEntity.setExpireTime(30000);
+ eventEntity.setAlarmContent("其他车主求助");
+ ADASUtils.broadcastToADAS(V2XServiceManager.getContext(), eventEntity);
+ }
+
+ @Override
+ public void show() {
+ showWindow();
+ drawPOI();
+ }
+
+ @Override
+ public void close() {
+ countDownFaultHelpWindowCancel();
+ super.close();
+ mV2XWindow = null;
+ mV2XMarker = null;
+ mV2XButton = null;
+ }
+
+ private volatile boolean isShown = false;
+ private ArrayBlockingQueue> blockingQueue = new ArrayBlockingQueue<>(5);
+ private CountDownTimer faultHelpTimer;
+
+ private void countDownFaultHelpWindowCancel() {
+ if (faultHelpTimer != null) {
+ faultHelpTimer.cancel();
+ faultHelpTimer = null;
+ }
+ blockingQueue.clear();
+ isShown = false;
+ }
+
+ private void countDownFaultHelpWindowStart() {
+ if (faultHelpTimer == null) {
+ faultHelpTimer = new CountDownTimer(20_000, 20_000) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ // Logger.d(TAG, "故障求助倒计时: " + millisUntilFinished);
+ }
+
+ @Override
+ public void onFinish() {
+ Logger.d(TAG, "故障求助倒计时: onFinish");
+ isShown = false;
+ List result = blockingQueue.poll();
+ closeWindow();
+ clearPOI();
+ if (result != null) {
+ mMarkerEntity = result;
+ show();
+ }
+ }
+
+ };
+ }
+ faultHelpTimer.start();
+ }
+
+ @Override
+ public void showWindow() {
+ V2XServiceManager.getMoGoV2XStatusManager().setOtherSeekHelpWindowShow(TAG, true);
+ if (mV2XWindow != null && mMarkerEntity != null) {
+ if (!isShown) {
+ isShown = true;
+ countDownFaultHelpWindowStart();
+ View view = mV2XWindow.getView();
+ Logger.d(TAG, "添加window= " + view);
+ ViewGroup.LayoutParams layoutParams =
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) V2XUtils.getApp().getResources().getDimension(R.dimen.module_v2x_fatigue_driving_window_height_ground));
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .addView(mV2XWindow.getView(), layoutParams,this);
+ mV2XWindow.show(mMarkerEntity);
+ } else {
+ blockingQueue.offer(mMarkerEntity);
+ }
+ }
+
+ }
+
+ @Override
+ public void closeWindow() {
+ if (V2XServiceManager.getMoGoV2XStatusManager().isOtherSeekHelpWindowShow()) {
+ Logger.d(TAG, "关闭求助车辆的Window!");
+ V2XServiceManager.getMoGoV2XStatusManager().setOtherSeekHelpWindowShow(TAG, false);
+ if (mV2XWindow != null) {
+ View view = mV2XWindow.getView();
+ Logger.d(TAG, "移除window= " + view);
+ V2XServiceManager
+ .getMogoTopViewManager()
+ .removeView(view);
+ mV2XWindow.close();
+ }
+ }
+ }
+
+ @Override
+ public void showButton() {
+
+ }
+
+ @Override
+ public void closeButton() {
+
+ }
+
+ @Override
+ public void drawPOI() {
+ if (mV2XMarker != null && mMarkerEntity != null) {
+ mV2XMarker.drawPOI(mMarkerEntity);
+ }
+ }
+
+ @Override
+ public void clearPOI() {
+ if (mV2XMarker != null) {
+ mV2XMarker.clearPOI();
+ }
+ }
+
+ @Override
+ public void onViewAdded(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 动画结束");
+ }
+
+ @Override
+ public void onViewRemoved(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 动画结束");
+ V2XServiceManager.getMoGoV2XStatusManager().setOtherSeekHelpWindowShow(TAG, false);
+ }
+
+ @Override
+ public void beforeViewAddAnim(View view) {
+ Logger.d(MODULE_NAME, "展示 Window 开始");
+ }
+
+ @Override
+ public void beforeViewRemoveAnim(View view) {
+ Logger.d(MODULE_NAME, "关闭 Window 开始");
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpWindow.java
new file mode 100644
index 0000000000..55cbc39080
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/seek/V2XSeekHelpWindow.java
@@ -0,0 +1,276 @@
+package com.mogo.module.v2x.scenario.scene.seek;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.PagerSnapHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.navi.IMogoNaviListener;
+import com.mogo.map.navi.MogoNaviInfo;
+import com.mogo.map.navi.MogoTraffic;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.adapter.V2XSeekHelpAdapter;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+import com.mogo.module.v2x.scenario.view.IV2XWindow;
+import com.mogo.module.v2x.voice.V2XVoiceCallbackListener;
+import com.mogo.module.v2x.voice.V2XVoiceConstants;
+import com.mogo.module.v2x.voice.V2XVoiceManager;
+import com.mogo.service.module.IMogoRegisterCenter;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.carchattingprovider.CallChattingProviderConstant;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.window
+ * @ClassName: V2XFaultHelpWindow
+ * @Description: 故障求助window
+ * @Author: fenghl
+ * @CreateDate: 2020/4/13 15:24
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/4/13 15:24
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class V2XSeekHelpWindow extends ConstraintLayout implements V2XSeekHelpAdapter.OnViewClickListener, IMogoNaviListener, IV2XWindow> {
+ private static final String TAG = V2XSeekHelpWindow.class.getSimpleName();
+ private RecyclerView mRecyclerView;
+ private int mCurPosition;
+ private V2XSeekHelpAdapter mAdapter;
+ IMogoRegisterCenter mMogoRegisterCenter = null;
+ private V2XMarkerEntity mMarkerEntity;
+ // 弹窗状态监听
+ private V2XWindowStatusListener mV2XWindowStatusListener;
+
+ public V2XSeekHelpWindow() {
+ this(V2XServiceManager.getContext(), null);
+ }
+ public V2XSeekHelpWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XSeekHelpWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XSeekHelpWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ private void init(Context context) {
+ Logger.w(MODULE_NAME, "初始化道路故障求助窗口View。。。。。");
+ LayoutInflater.from(context).inflate(R.layout.window_fault_help, this);
+ initRecyclerView(context);
+ initVoice();
+ mMogoRegisterCenter = V2XServiceManager.getMogoRegisterCenter();
+ }
+
+ private void initRecyclerView(Context context) {
+ mRecyclerView = findViewById(R.id.rvFaultHelp);
+ LinearLayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.VERTICAL, false);
+ mRecyclerView.setLayoutManager(layoutManager);
+ mAdapter = new V2XSeekHelpAdapter(context);
+ mAdapter.setOnViewClickListener(this);
+ mRecyclerView.setAdapter(mAdapter);
+
+ mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (recyclerView.getChildCount() > 0 && newState == RecyclerView.SCROLL_STATE_IDLE) {
+ mCurPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
+ Logger.d(TAG, "v2x 故障求助 当前显示位置===" + mCurPosition);
+ }
+ }
+ });
+ new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+ }
+
+ private V2XVoiceCallbackListener mChatCb = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ if (mMarkerEntity != null) {
+ callChatting(mMarkerEntity);
+ }
+ }
+ };
+ private V2XVoiceCallbackListener mNaviCb = new V2XVoiceCallbackListener() {
+ @Override
+ public void onCallback(String command, Intent intent) {
+ if (mMarkerEntity != null) {
+ startNavi(mMarkerEntity.getLat(), mMarkerEntity.getLon());
+ }
+ }
+ };
+
+ /**
+ * 注册语音
+ */
+ private void initVoice() {
+ registerVoiceCmd();
+ }
+
+ private void registerVoiceCmd() {
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING, mChatCb);
+ V2XVoiceManager.INSTANCE.registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP, mChatCb);
+ V2XVoiceManager.INSTANCE.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI, mNaviCb);
+ V2XVoiceManager.INSTANCE.registerUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP, mNaviCb);
+ }
+
+ private void unregisterVoiceCmd() {
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_CALL_CHATTING);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_CHAT_MORE_UN_WAKEUP);
+ V2XVoiceManager.INSTANCE.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_NAVI);
+ V2XVoiceManager.INSTANCE.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_V2X_TO_NAVI_UN_WAKEUP);
+ }
+
+
+ private void callChatting(V2XMarkerEntity entity) {
+ try {
+ Map params = new HashMap<>(16);
+ params.put(CallChattingProviderConstant.CCPROVIDER_SN, entity.getSn());
+ V2XMarkerEntity.UserInfoBean infoBean = entity.getUserInfo();
+ if (infoBean != null) {
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_IMG, infoBean.getHeadImgUrl());
+
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_AGE, infoBean.getAge() + "");
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_SEX, infoBean.getSex() + "");
+ params.put(CallChattingProviderConstant.CCPROVIDER_NICK_NAME, infoBean.getDisplayName());
+ }
+// params.put(CallChattingProviderConstant.CCPROVIDER_CAR_TYPE, );
+
+ //params.put(CallChattingProviderConstant.CCPROVIDER_ADDRESS, location.getAddress());
+ params.put(CallChattingProviderConstant.CCPROVIDER_LAT, entity.getLat() + "");
+ params.put(CallChattingProviderConstant.CCPROVIDER_LON, entity.getLon() + "");
+
+
+ Logger.d(TAG, "调用车聊聊传入参数==$params===" + params);
+ V2XServiceManager.getCarsChattingProvider().call(params);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onViewChatClick(V2XMarkerEntity entity) {
+ Log.d(TAG, "点击:调用车聊聊通话!");
+ callChatting(entity);
+ }
+
+ @Override
+ public void onViewNaviClick(double lat, double lng) {
+ startNavi(lat, lng);
+ }
+
+ private void startNavi(double lat, double lng) {
+ Log.d(TAG, "去导航!");
+ MogoLatLng endPoint = new MogoLatLng(lat, lng);
+ V2XServiceManager.getNavi().naviTo(endPoint);
+ synchronized (V2XSeekHelpWindow.class) {
+ mMogoRegisterCenter.unregisterMogoNaviListener(MODULE_NAME);
+ mMogoRegisterCenter.registerMogoNaviListener(MODULE_NAME, this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ unregisterVoiceCmd();
+ mAdapter.clearData();
+ mAdapter.setOnViewClickListener(null);
+ synchronized (V2XSeekHelpWindow.class) {
+ mMogoRegisterCenter.unregisterMogoNaviListener(MODULE_NAME);
+ }
+ mMarkerEntity = null;
+
+ }
+
+ @Override
+ public void onInitNaviFailure() {
+
+ }
+
+ @Override
+ public void onInitNaviSuccess() {
+
+ }
+
+ @Override
+ public void onNaviInfoUpdate(MogoNaviInfo naviinfo) {
+
+ }
+
+ @Override
+ public void onStartNavi() {
+
+ }
+
+ @Override
+ public void onStopNavi() {
+
+ }
+
+ @Override
+ public void onCalculateSuccess() {
+ V2XServiceManager.getNavi().startNavi(true);
+ }
+
+ @Override
+ public void onoCalculateFailed() {
+
+ }
+
+ @Override
+ public void onUpdateTraffic(MogoTraffic traffic) {
+
+ }
+
+
+ @Override
+ public void show(List entityList) {
+ // TODO: 2020/4/13 根据需求仅展示一个,默认显示第一个
+ if (entityList != null && !entityList.isEmpty()) {
+ V2XMarkerEntity entity = entityList.get(0);
+ mAdapter.addData(entityList.get(0));
+ mAdapter.notifyDataSetChanged();
+ mMarkerEntity = entity;
+ }
+ //mAdapter.addDataList(entityList);
+ }
+
+ @Override
+ public void close() {
+ /* Logger.d(TAG,"移除window= "+this);
+ V2XServiceManager
+ .getIMogoWindowManager()
+ .removeView(this);*/
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public void setWindowStatusListener(V2XWindowStatusListener listener) {
+ mV2XWindowStatusListener = listener;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/test/V2XTestConsoleWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/test/V2XTestConsoleWindow.java
new file mode 100644
index 0000000000..db742c9792
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/scene/test/V2XTestConsoleWindow.java
@@ -0,0 +1,130 @@
+package com.mogo.module.v2x.scenario.scene.test;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes;
+import com.mogo.module.v2x.utils.TestOnLineCarUtils;
+
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/24 11:34 AM
+ * desc : 用来测试的控制台 Window
+ * version: 1.0
+ */
+public class V2XTestConsoleWindow extends ConstraintLayout {
+
+ private Button mBtnTriggerRoadEvent;
+ private Button mBtnTriggerPushEvent;
+ private Button mBtnTriggerPushLiveCarEvent;
+ private Button mBtnTriggerAnimationEvent;
+ private Button mBtnTriggerFatigueDrivingEvent;
+ private Button mBtnTriggerSeekHelpEvent;
+ private Button mBtnTriggerParkEvent;
+
+ public V2XTestConsoleWindow(Context context) {
+ this(context, null);
+ }
+
+ public V2XTestConsoleWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public V2XTestConsoleWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ private void initView(Context context) {
+ LayoutInflater.from(context).inflate(R.layout.window_test_console, this);
+
+ mBtnTriggerRoadEvent = findViewById(R.id.btnTriggerRoadEvent);
+ mBtnTriggerPushEvent = findViewById(R.id.btnTriggerPushEvent);
+ mBtnTriggerPushLiveCarEvent = findViewById(R.id.btnTriggerPushLiveCarEvent);
+ mBtnTriggerAnimationEvent = findViewById(R.id.btnTriggerAnimationEvent);
+ mBtnTriggerFatigueDrivingEvent = findViewById(R.id.btnTriggerFatigueDrivingEvent);
+ mBtnTriggerSeekHelpEvent = findViewById(R.id.btnTriggerSeekHelpEvent);
+ mBtnTriggerParkEvent = findViewById(R.id.btnTriggerParkEvent);
+
+ mBtnTriggerRoadEvent.setOnClickListener(v -> {
+ V2XMessageEntity v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioRoadEventData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+ mBtnTriggerPushEvent.setOnClickListener(v -> {
+ V2XMessageEntity v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioPushEventData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+ mBtnTriggerPushLiveCarEvent.setOnClickListener(v -> {
+ V2XMessageEntity v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioPushEventData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+ mBtnTriggerAnimationEvent.setOnClickListener(v -> {
+ V2XMessageEntity v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioAnimationEventData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+ mBtnTriggerFatigueDrivingEvent.setOnClickListener(v -> {
+ V2XMessageEntity v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioFatigueDrivingData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+ mBtnTriggerSeekHelpEvent.setOnClickListener(v -> {
+ V2XMessageEntity> v2XMessageEntity =
+ TestOnLineCarUtils.getV2XScenarioSeekHelpData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+
+
+ mBtnTriggerParkEvent.setOnClickListener(v -> {
+ V2XMessageEntity> v2XMessageEntity =
+ TestOnLineCarUtils.getV2XIllegalParkData();
+
+ Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
+ intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ });
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButton.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButton.java
new file mode 100644
index 0000000000..9ff7d04cc0
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButton.java
@@ -0,0 +1,38 @@
+package com.mogo.module.v2x.scenario.view;
+
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 5:02 PM
+ * desc :
+ * version: 1.0
+ */
+public interface IV2XButton {
+ /**
+ * 设置监听器,处理button点击和语音唤醒
+ * @param listener
+ */
+ void setOnActionListener(IV2XButtonListener listener);
+
+ /**
+ * 按钮显示
+ */
+ void show();
+
+ /**
+ * 按钮关闭
+ */
+ void close();
+
+ /**
+ * 语音注册
+ */
+ void registerVoice();
+
+ /**
+ * 语音反注册
+ */
+ void unRegisterVoice();
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButtonListener.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButtonListener.java
new file mode 100644
index 0000000000..6d9876fc99
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XButtonListener.java
@@ -0,0 +1,22 @@
+package com.mogo.module.v2x.scenario.view;
+
+import android.view.View;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.scenario.view
+ * @ClassName: IV2XButtonListener
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/5/18 15:58
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/18 15:58
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public interface IV2XButtonListener {
+ /**
+ * 响应点击或语音触发事件
+ */
+ void onAction();
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XMarker.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XMarker.java
new file mode 100644
index 0000000000..eb46fdef6a
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XMarker.java
@@ -0,0 +1,16 @@
+package com.mogo.module.v2x.scenario.view;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 4:13 PM
+ * desc : V2X安全驾驶场景接口
+ * version: 1.0
+ */
+public interface IV2XMarker {
+
+ void drawPOI(T entity);
+
+ void clearPOI();
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XWindow.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XWindow.java
new file mode 100644
index 0000000000..55159f0338
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/scenario/view/IV2XWindow.java
@@ -0,0 +1,44 @@
+package com.mogo.module.v2x.scenario.view;
+
+import android.view.View;
+
+import com.mogo.module.v2x.listener.V2XWindowStatusListener;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.statusmanager
+ * @ClassName: IV2XWindow
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/5/15 11:24
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/15 11:24
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public interface IV2XWindow {
+
+ /**
+ * 展示1/2窗口
+ */
+ void show(T entity);
+
+ /**
+ * 关闭1/2窗口
+ */
+ void close();
+
+ /**
+ * 返回窗体
+ *
+ * @return 当前窗体
+ */
+ View getView();
+
+ /**
+ * 设置Window状态监听
+ *
+ * @param listener 监听器
+ */
+ void setWindowStatusListener(V2XWindowStatusListener listener);
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ADASUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ADASUtils.java
new file mode 100644
index 0000000000..26e1e56bd4
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ADASUtils.java
@@ -0,0 +1,139 @@
+package com.mogo.module.v2x.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
+import com.mogo.commons.voice.VoicePreemptType;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.entity.net.V2XAlarmEventRes;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.utils.AppUtils;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/3 6:54 PM
+ * desc :
+ * version: 1.0
+ */
+public class ADASUtils {
+ /**
+ * 广播给ADAS进行展示
+ *
+ * @param v2XRoadEventEntity 广播信息
+ */
+ public static void broadcastToADAS(Context context, V2XRoadEventEntity v2XRoadEventEntity) {
+ try {
+ V2XPushMessageEntity v2XAlarmMessage = new V2XPushMessageEntity();
+ v2XAlarmMessage.setTts(v2XRoadEventEntity.getTts());
+ v2XAlarmMessage.setAlarmContent(v2XRoadEventEntity.getAlarmContent());
+ v2XAlarmMessage.setExpireTime(v2XRoadEventEntity.getExpireTime());
+ v2XAlarmMessage.setSceneId(v2XRoadEventEntity.getPoiType());
+
+ broadcastToADAS(context, v2XAlarmMessage);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 广播给ADAS进行展示
+ *
+ * @param alarmInfo 广播信息
+ */
+ public static void broadcastToADAS(Context context, V2XAlarmEventRes.AlarmInfo alarmInfo) {
+ try {
+ V2XPushMessageEntity v2XAlarmMessage = new V2XPushMessageEntity();
+ v2XAlarmMessage.setTts(alarmInfo.getTts());
+ v2XAlarmMessage.setAlarmContent(alarmInfo.getAlarmContent());
+ v2XAlarmMessage.setExpireTime(alarmInfo.getExpireTime());
+ v2XAlarmMessage.setSceneId(alarmInfo.getPoiType());
+
+ broadcastToADAS(context, v2XAlarmMessage);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 广播给ADAS进行展示
+ *
+ * @param alarmMessage 广播信息
+ */
+ public static void broadcastToADAS(Context context, V2XPushMessageEntity alarmMessage) {
+ try {
+ Intent intent = new Intent("com.mogo.launcher.v2x");
+ intent.putExtra("v2x_warning_type", alarmMessage.getSceneId());
+ intent.putExtra("v2x_warining_timeout", alarmMessage.getExpireTime());
+ intent.putExtra("v2x_warning_tts", alarmMessage.getTts());
+ intent.putExtra("v2x_warning_info", alarmMessage.getAlarmContent());
+ context.sendBroadcast(intent);
+
+ // 这里是兼容 1+16G 版本没有ADAS的时候自身进行TTS
+ if (!AppUtils.isAppInstalled(context, "com.zhidao.autopilot")) {
+ speakTTSVoice(alarmMessage.getTts(), null);
+ }
+
+ Logger.i(MODULE_NAME, "向ADAS分发服务器下发的事件," + alarmMessage.toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 广播给ADAS进行展示
+ *
+ * @param alarmInfo 广播信息
+ */
+ public static void broadcastToADAS_TTS(Context context, V2XAlarmEventRes.AlarmInfo alarmInfo) {
+ try {
+ V2XPushMessageEntity v2XAlarmMessage = new V2XPushMessageEntity();
+ v2XAlarmMessage.setTts(alarmInfo.getTts());
+ v2XAlarmMessage.setAlarmContent(alarmInfo.getAlarmContent());
+ v2XAlarmMessage.setExpireTime(alarmInfo.getExpireTime());
+ v2XAlarmMessage.setSceneId(alarmInfo.getPoiType());
+
+ broadcastToADAS_TTS(context, v2XAlarmMessage);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 广播给ADAS进行TTS播报
+ *
+ * @param alarmMessage 广播信息
+ */
+ public static void broadcastToADAS_TTS(Context context, V2XPushMessageEntity alarmMessage) {
+ try {
+ Intent intent = new Intent("com.mogo.launcher.v2x.tts");
+ intent.putExtra("v2x_warning_tts", alarmMessage.getTts());
+ context.sendBroadcast(intent);
+
+ // 这里是兼容 1+16G 版本没有ADAS的时候自身进行TTS
+ if (!AppUtils.isAppInstalled(context, "com.zhidao.autopilot")) {
+ speakTTSVoice(alarmMessage.getTts(), null);
+ }
+
+ Logger.i(MODULE_NAME, "向ADAS分发服务器下发的事件," + alarmMessage.toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void speakTTSVoice(@Nullable String msg, IMogoVoiceCmdCallBack callBack) {
+ if (!TextUtils.isEmpty(msg)) {
+ Logger.w(V2XConst.MODULE_NAME, "调用TTS播放语音:" + msg);
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice(msg, VoicePreemptType.PREEMPT_TYPE_IMMEADIATELY, callBack);
+ }
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ChartingUtil.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ChartingUtil.java
new file mode 100644
index 0000000000..c507a39220
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ChartingUtil.java
@@ -0,0 +1,101 @@
+package com.mogo.module.v2x.utils;
+
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerUserInfo;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.carchattingprovider.CallChattingProviderConstant;
+import com.zhidao.carchattingprovider.ICallChatResponse;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/15 4:26 PM
+ * desc : 调用车聊聊的工具类
+ * version: 1.0
+ */
+public class ChartingUtil {
+ public interface ChartStatusListener {
+ void canCall(boolean b);
+ }
+
+ /**
+ * 调用车聊聊拨打电话
+ *
+ * @param userInfo 用户数据
+ * @param location 位置信息
+ */
+ public static void callChatting(MarkerUserInfo userInfo, MarkerLocation location) {
+ try {
+ Map params = new HashMap<>();
+ params.put(CallChattingProviderConstant.CCPROVIDER_SN, userInfo.getSn());
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_IMG, userInfo.getUserHead());
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_AGE, userInfo.getAgeNumber() + "");
+ params.put(CallChattingProviderConstant.CCPROVIDER_NICK_NAME, userInfo.getUserName());
+ params.put(CallChattingProviderConstant.CCPROVIDER_USER_SEX, userInfo.getGender() + "");
+
+ if (location != null) {
+ params.put(CallChattingProviderConstant.CCPROVIDER_ADDRESS, location.getAddress());
+ params.put(CallChattingProviderConstant.CCPROVIDER_LAT, location.getLat() + "");
+ params.put(CallChattingProviderConstant.CCPROVIDER_LON, location.getLon() + "");
+ }
+
+ Logger.d(MODULE_NAME, "调用车聊聊传入参数:\n" + params);
+ V2XServiceManager.getCarsChattingProvider().call(params);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 判断是否可以拨打电话
+ *
+ * @param chartStatusListener 车聊聊状态监听
+ */
+ public static void isOnLine(String sn, ChartStatusListener chartStatusListener) {
+ V2XServiceManager.getCarsChattingProvider().isOnLine(
+ "CAR_CALL_TO_" + V2XConst.MODULE_NAME,
+ V2XUtils.getApp(),
+ sn,
+ new ICallChatResponse() {
+ @Override
+ public void isOnLine(boolean onLine, @Nullable String errorMsg) {
+ Logger.e(V2XConst.MODULE_NAME, "isOnLine:" + onLine + " errorMsg:" + errorMsg);
+ if (chartStatusListener != null) {
+ chartStatusListener.canCall(onLine);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * 判断是否可以拨打电话
+ *
+ * @param chartStatusListener 车聊聊状态监听
+ */
+ public static void isCanCall(ChartStatusListener chartStatusListener) {
+ V2XServiceManager.getCarsChattingProvider().canCall(
+ "CAR_CALL_TO_" + V2XConst.MODULE_NAME,
+ V2XUtils.getApp(),
+ new ICallChatResponse() {
+ @Override
+ public void canCall(boolean onLine) {
+ Logger.e(V2XConst.MODULE_NAME, "isOnLine:" + onLine);
+
+ if (chartStatusListener != null) {
+ chartStatusListener.canCall(onLine);
+ }
+ }
+ });
+
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/DrivingDirectionUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/DrivingDirectionUtils.java
new file mode 100644
index 0000000000..f045b6d0c1
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/DrivingDirectionUtils.java
@@ -0,0 +1,109 @@
+package com.mogo.module.v2x.utils;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/14 1:02 PM
+ * desc : 计算车辆驾驶方向的工具类
+ * version: 1.0
+ */
+public class DrivingDirectionUtils {
+
+ /**
+ * 计算车辆行驶方向 与 poi点到车辆的连线 间的夹角
+ *
+ * @param carLon 车辆位置 lon
+ * @param carLat 车辆位置 lat
+ * @param poiLon poi 位置 lon
+ * @param poiLat poi 位置 lat
+ * @param carAngle 车辆行驶方向
+ * @return
+ */
+ public static int getDegreeOfCar2Poi(double carLon, double carLat, double poiLon, double poiLat, int carAngle) {
+ int poiAngle = 0;
+ // 以子午线作为y轴 计算两点的余切 再将余切值转化为角度
+ double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / Math.PI);
+
+ if (poiLon > carLon) {
+ // poi 在 车辆位置的第1象限
+ if (poiLat > carLat) {
+ poiAngle = (int) _angle;
+ }
+ // poi 在 车辆位置的第2象限
+ else {
+ poiAngle = 180 - (int) _angle;
+ }
+ } else {
+ // poi 在 车辆位置的第3象限
+ if (poiLat < carLat) {
+ poiAngle = (int) _angle + 180;
+ }
+ // poi 在 车辆位置的第4象限
+ else {
+ poiAngle = 360 - (int) _angle;
+ }
+ }
+ return calculationAngle(poiAngle, carAngle);
+ }
+
+
+ /**
+ * 计算车辆行驶方向 与 poi点到车辆的连线 间的夹角
+ *
+ * @param carLat 车辆位置 lat
+ * @param carLon 车辆位置 lon
+ * @param poiLat poi 位置 lat
+ * @param poiLon poi 位置 lon
+ */
+ public static int getCarAngle(double carLat, double carLon, double poiLat, double poiLon) {
+ int poiAngle = 0;
+ // 以子午线作为y轴 计算两点的余切 再将余切值转化为角度
+ double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / Math.PI);
+
+ if (poiLon > carLon) {
+ // poi 在 车辆位置的第1象限
+ if (poiLat > carLat) {
+ poiAngle = (int) _angle;
+ }
+ // poi 在 车辆位置的第2象限
+ else {
+ poiAngle = 180 - (int) _angle;
+ }
+ } else {
+ // poi 在 车辆位置的第3象限
+ if (poiLat < carLat) {
+ poiAngle = (int) _angle + 180;
+ }
+ // poi 在 车辆位置的第4象限
+ else {
+ poiAngle = 360 - (int) _angle;
+ }
+ }
+
+ if (poiAngle >= 355) {
+ poiAngle = 0;
+ }
+ return poiAngle;
+ }
+
+ /**
+ * 计算两个行驶方向间的夹角 计算结果小于180度
+ *
+ * @param angle0
+ * @param angle1
+ * @return
+ */
+ public static int calculationAngle(int angle0, int angle1) {
+ // 获取两方向间夹角
+ int angle = Math.abs(angle0 - angle1);
+ if (angle > 180) {
+ int minAngle = Math.min(angle0, angle1);
+ int maxAngle = Math.max(angle0, angle1);
+ return 180 - Math.abs(minAngle + 180 - maxAngle);
+ } else {
+ return angle;
+ }
+ }
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/EventTypeUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/EventTypeUtils.java
new file mode 100644
index 0000000000..e70f2114cd
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/EventTypeUtils.java
@@ -0,0 +1,125 @@
+package com.mogo.module.v2x.utils;
+
+import com.mogo.module.v2x.R;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+
+/**
+ * @ProjectName: MoGoModulSafeDriving
+ * @Package: com.mogo.module.v2x.utils
+ * @ClassName: EventTypeUtils
+ * @Description: java类作用描述
+ * @Author: fenghl
+ * @CreateDate: 2020/5/20 17:10
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2020/5/20 17:10
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class EventTypeUtils {
+ public static String getPoiTypeStr(String poiType) {
+ String str = "其它道路事件";
+ switch (poiType) {
+ // 停车场
+ case V2XPoiTypeEnum.FOURS_PARKING:
+ str = "停车场";
+ break;
+ // 加油站
+ case V2XPoiTypeEnum.GAS_STATION:
+ str = "加油站";
+ break;
+ // 交通检查
+ case V2XPoiTypeEnum.TRAFFIC_CHECK:
+ str = "交通检查";
+ break;
+ // 封路
+ case V2XPoiTypeEnum.ROAD_CLOSED:
+ str = "封路";
+ break;
+ // 施工
+ case V2XPoiTypeEnum.FOURS_ROAD_WORK:
+ str = "道路施工";
+ break;
+ // 拥堵
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ str = "道路拥堵";
+ break;
+ // 积水
+ case V2XPoiTypeEnum.FOURS_PONDING:
+ str = "道路积水";
+ break;
+ // 浓雾
+ case V2XPoiTypeEnum.FOURS_FOG:
+ str = "出现浓雾";
+ break;
+ // 结冰
+ case V2XPoiTypeEnum.FOURS_ICE:
+ str = "路面结冰";
+ break;
+ // 事故
+ case V2XPoiTypeEnum.FOURS_ACCIDENT:
+ str = "交通事故";
+ break;
+ default:
+ str = "其它道路事件";
+ break;
+ }
+ return str;
+ }
+
+ /**
+ * 获取道路事件的背景色
+ *
+ * @param poiType poi类型
+ * @return 背景
+ */
+ public static int getPoiTypeBg(String poiType) {
+ int strBg;
+ switch (poiType) {
+ case V2XPoiTypeEnum.FOURS_PARKING: // 停车场
+ case V2XPoiTypeEnum.GAS_STATION: // 加油站
+ strBg = R.drawable.bg_v2x_event_type_blue;
+ break;
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP: // 拥堵
+ strBg = R.drawable.bg_v2x_event_type_orange;
+ break;
+ case V2XPoiTypeEnum.TRAFFIC_CHECK:// 交通检查
+ case V2XPoiTypeEnum.ROAD_CLOSED:// 封路
+ case V2XPoiTypeEnum.FOURS_ROAD_WORK:// 施工
+ case V2XPoiTypeEnum.FOURS_PONDING:// 积水
+ case V2XPoiTypeEnum.FOURS_FOG: // 浓雾
+ case V2XPoiTypeEnum.FOURS_ICE: // 结冰
+ case V2XPoiTypeEnum.FOURS_ACCIDENT: // 事故
+ strBg = R.drawable.bg_v2x_event_type_read;
+ break;
+ default:
+ strBg = R.drawable.bg_v2x_event_type_read;
+ break;
+ }
+ return strBg;
+ }
+
+
+ /**
+ * 判断是否是道路预警事件
+ *
+ * @param poiType
+ * @return
+ */
+ public static boolean isRoadEvent(String poiType) {
+ boolean isRoadEvent = false;
+ // 进行类型分发
+ switch (poiType) {
+ case V2XPoiTypeEnum.TRAFFIC_CHECK: // 交通检查
+ case V2XPoiTypeEnum.ROAD_CLOSED://封路
+ case V2XPoiTypeEnum.FOURS_ROAD_WORK://施工
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP://拥堵
+ case V2XPoiTypeEnum.FOURS_PONDING://积水
+ case V2XPoiTypeEnum.FOURS_FOG://浓雾
+ case V2XPoiTypeEnum.FOURS_ICE://结冰
+ case V2XPoiTypeEnum.FOURS_ACCIDENT://事故
+ isRoadEvent = true;
+ break;
+ }
+ return isRoadEvent;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/FatigueDrivingUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/FatigueDrivingUtils.java
new file mode 100644
index 0000000000..0322137b9d
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/FatigueDrivingUtils.java
@@ -0,0 +1,82 @@
+package com.mogo.module.v2x.utils;
+
+import android.text.TextUtils;
+
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.entity.net.V2XStrategyPushRes;
+import com.mogo.utils.logger.Logger;
+import com.mogo.utils.storage.SharedPrefsMgr;
+import com.zhidao.utils.common.GsonUtil;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/26 3:12 PM
+ * desc : 疲劳驾驶的工具类
+ * version: 1.0
+ */
+public class FatigueDrivingUtils {
+
+ /**
+ * 获取驾驶时常
+ *
+ * @return 驾驶市场
+ */
+ public static long getDrivingTime() {
+ // 获取 ACC ON 时间
+ String accOnTime = SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .getString(V2XConst.V2X_ACC_ON_TIME_STR);
+ if (TextUtils.isEmpty(accOnTime)) {
+ accOnTime = TimeUtils.getNowString();
+ // 记录开机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_ON_TIME_STR, accOnTime);
+ }
+ return Math.abs(TimeUtils.getTimeSpanByNow(accOnTime, TimeConstants.MIN));
+ }
+
+ /**
+ * 刷新ACC ON时间记录
+ * 获取上次记录的开机事件,判断如果当前acc on时间与上次acc off时间<20min的忽略
+ */
+ public static void refreshAccOnTime() {
+ // 获取 ACC ON 时间
+ String localAccONTime = SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .getString(V2XConst.V2X_ACC_ON_TIME_STR);
+ Logger.d(V2XConst.MODULE_NAME, "ACC ON时间:" + localAccONTime);
+
+ // 如果本地没有记录时间则记录
+ if (!TextUtils.isEmpty(localAccONTime)) {
+ // 获取配置信息
+ V2XStrategyPushRes.ResultBean strategyPushEntity =
+ GsonUtil.objectFromJson(SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .getString(V2XConst.V2X_STRATEGY_PUSH), V2XStrategyPushRes.ResultBean.class);
+ if (strategyPushEntity != null) {
+ // 获取 当前 ACC ON 时间
+ String accOnTime = TimeUtils.getNowString();
+ // 获取 ACC OFF 时间
+ String accOFFTime = SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .getString(V2XConst.V2X_ACC_OFF_TIME_STR);
+ if (!TextUtils.isEmpty(accOFFTime)) {
+ // 比较开关机时间,如果acc of 比 acc on 时间还要靠近说明acc on 时间记录有问题,需要更新同步
+ long timeSpan = TimeUtils.getTimeSpan(accOnTime, accOFFTime, TimeConstants.MIN);
+ Logger.d(V2XConst.MODULE_NAME, "开关机时间间隔:" + timeSpan);
+ if (timeSpan >= strategyPushEntity.getRestIgnoreMinutes()) {
+ // 记录开机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_ON_TIME_STR, accOnTime);
+ }
+ }
+ } else {
+ // 记录开机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_ON_TIME_STR, TimeUtils.getNowString());
+ }
+ } else {
+ // 记录开机时间
+ SharedPrefsMgr.getInstance(V2XUtils.getApp())
+ .putString(V2XConst.V2X_ACC_ON_TIME_STR, TimeUtils.getNowString());
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ImageUtil.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ImageUtil.java
new file mode 100644
index 0000000000..76ba3e4c03
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ImageUtil.java
@@ -0,0 +1,78 @@
+package com.mogo.module.v2x.utils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.text.TextUtils;
+
+/**
+ * 图片工具来
+ */
+public class ImageUtil {
+
+ /**
+ * 根据需求的宽和高以及图片实际的宽和高计算SampleSize
+ */
+ public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth,
+ int reqHeight) {
+ int width = options.outWidth;
+ int height = options.outHeight;
+
+ int inSampleSize = 1;
+
+ if (width > reqWidth || height > reqHeight) {
+ int widthRadio = Math.round(width * 1.0f / reqWidth);
+ int heightRadio = Math.round(height * 1.0f / reqHeight);
+
+ inSampleSize = Math.max(widthRadio, heightRadio);
+ }
+
+ return inSampleSize;
+ }
+
+ /**
+ * 根据要求的宽高,从本地路径得到bitmap
+ *
+ * @param picPath
+ * @param width
+ * @param height
+ * @return
+ */
+ public static Bitmap createBitmap(String picPath, int width, int height) {
+ if (!TextUtils.isEmpty(picPath)) {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+// opts.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(picPath, opts);
+// opts.inSampleSize = caculateInSampleSize(opts, width, height);
+// opts.inJustDecodeBounds = false;
+ Bitmap bitmap = BitmapFactory.decodeFile(picPath, opts);
+ return bitmap;
+ }
+ return null;
+ }
+
+ public static Bitmap createBitmap(Context context, int resId, int width, int height) {
+ if (resId != 0) {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+// opts.inJustDecodeBounds = true;
+ BitmapFactory.decodeResource(context.getResources(), resId, opts);
+// opts.inSampleSize = caculateInSampleSize(opts, width, height);
+// opts.inJustDecodeBounds = false;
+ Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId, opts);
+ return bitmap;
+ }
+ return null;
+ }
+
+ public static Bitmap getBitmap(Context context, Object path, int width, int height) {
+ Bitmap bitmap = null;
+ if (path instanceof String) {
+ bitmap = createBitmap((String) path, width, height);
+ } else if (path instanceof Integer) {
+ if (context != null) {
+ bitmap = createBitmap(context, (Integer) path, width, height);
+ }
+ }
+ return bitmap;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/LocationUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/LocationUtils.java
new file mode 100644
index 0000000000..a3a8f4aed5
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/LocationUtils.java
@@ -0,0 +1,88 @@
+package com.mogo.module.v2x.utils;
+
+import android.location.Location;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.location.MogoLocation;
+import com.mogo.map.search.geo.IMogoGeoSearchListener;
+import com.mogo.map.search.geo.MogoGeocodeResult;
+import com.mogo.map.search.geo.MogoPoiItem;
+import com.mogo.map.search.geo.MogoRegeocodeResult;
+import com.mogo.map.search.geo.query.MogoRegeocodeQuery;
+import com.mogo.map.search.poisearch.IMogoPoiSearch;
+import com.mogo.map.search.poisearch.IMogoPoiSearchListener;
+import com.mogo.map.search.poisearch.MogoPoiResult;
+import com.mogo.map.search.poisearch.query.MogoPoiSearchQuery;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.utils.logger.Logger;
+import com.zhidao.utils.common.GsonUtil;
+
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/5/15 10:31 AM
+ * desc : 基于位置工具类
+ * version: 1.0
+ */
+public class LocationUtils {
+ private static final String TAG = "LocationUtils";
+
+ public static void geoCodeSearch(MogoLocation location,IMogoGeoSearchListener listener) {
+ MogoRegeocodeQuery mogoRegeocodeQuery = new MogoRegeocodeQuery();
+ mogoRegeocodeQuery.setPoint(new MogoLatLng(location.getLatitude(), location.getLongitude()));
+
+ V2XServiceManager.getMogoGeoSearch().setGeoSearchListener(listener);
+
+ V2XServiceManager.getMogoGeoSearch().getFromLocationAsyn(mogoRegeocodeQuery);
+ }
+
+ /**
+ * 根据关键词进行查询
+ */
+ public static void searchPOI(String keyword) {
+ MogoPoiSearchQuery poiSearchQuery = new MogoPoiSearchQuery(keyword, keyword);
+ poiSearchQuery.setPageSize(10);
+ poiSearchQuery.setLocation(getCurrentLatLon());
+ IMogoPoiSearch poiSearch = V2XServiceManager.getMapService().getPoiSearch(V2XUtils.getApp(), poiSearchQuery);
+
+ poiSearch.setPoiSearchListener(new IMogoPoiSearchListener() {
+ @Override
+ public void onPoiSearched(MogoPoiResult result, int errorCode) {
+ Logger.i(V2XConst.MODULE_NAME,
+ "keyword: " + keyword +
+ "\nPOI查询结果为:" + GsonUtil.jsonFromObject(result.getPois()));
+ }
+
+ @Override
+ public void onPoiItemSearched(MogoPoiItem item, int errorCode) {
+
+ }
+ });
+ poiSearch.searchPOIAsyn();
+ }
+
+ public static MogoLatLng getCurrentLatLon() {
+ MogoLatLng latLon = V2XServiceManager.getNavi().getCarLocation();
+ if (latLon == null) {
+ Location location = V2XServiceManager.getNavi().getCarLocation2();
+ if (location != null) {
+ latLon = new MogoLatLng(location.getLatitude(), location.getLongitude());
+ }
+ }
+ if (latLon == null) {
+ MogoLocation location = V2XServiceManager.getMogoLocationClient().getLastKnowLocation();
+ if (location != null) {
+ latLon = new MogoLatLng(location.getLatitude(), location.getLongitude());
+ }
+ }
+ if (latLon == null) {
+ latLon = V2XServiceManager.getMapUIController().getWindowCenterLocation();
+ }
+ return latLon;
+ }
+
+
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/MarkerUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/MarkerUtils.java
new file mode 100644
index 0000000000..f31fb111d0
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/MarkerUtils.java
@@ -0,0 +1,141 @@
+package com.mogo.module.v2x.utils;
+
+import android.content.Context;
+import android.graphics.Rect;
+
+import com.mogo.map.MogoLatLng;
+import com.mogo.map.marker.IMogoMarkerClickListener;
+import com.mogo.module.common.entity.MarkerLocation;
+import com.mogo.module.common.entity.MarkerShowEntity;
+import com.mogo.module.common.utils.CarSeries;
+import com.mogo.module.v2x.V2XConst;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes.V2XMarkerEntity;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.utils.WindowUtils;
+import com.mogo.utils.logger.Logger;
+
+import java.util.Collections;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/3 5:52 PM
+ * desc :
+ * version: 1.0
+ */
+@Deprecated
+public class MarkerUtils {
+ private static final String TAG = "MarkerUtils";
+
+ /**
+ * 特殊车辆推送绘制,实时更新的
+ *
+ * @param v2XSpecialCarRes 绘制地图气泡
+ */
+ public static void handlerV2XSpecialVehicleMarker(V2XSpecialCarRes v2XSpecialCarRes,
+ Context context,
+ IMogoMarkerClickListener clickListener) {
+ try {
+ // 移除上一次的数据
+ V2XServiceManager.getMarkerManager().removeMarkers(V2XConst.V2X_MARKER_SPECIAL_CAR);
+ // 循环绘制
+ for (V2XMarkerEntity v2XMarkerEntity : v2XSpecialCarRes.getCoordinates()) {
+ if (v2XMarkerEntity.getTargetId() != V2XPoiTypeEnum.ALERT_CAR_TROUBLE_WARNING) {
+ MarkerLocation markerLocation = new MarkerLocation();
+ markerLocation.setLon(v2XMarkerEntity.getLon());
+ markerLocation.setLat(v2XMarkerEntity.getLat());
+ // 进行数据转换,用于Marker展示
+ MarkerShowEntity markerShowEntity = new MarkerShowEntity();
+ markerShowEntity.setMarkerLocation(markerLocation);
+ markerShowEntity.setMarkerType(V2XConst.V2X_MARKER_SPECIAL_CAR);
+ markerShowEntity.setBindObj(v2XMarkerEntity);
+ V2XServiceManager.getMoGoV2XMarkerManager().drawableMarker(context, markerShowEntity, clickListener);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 自动调整地图的镜头
+ */
+ public static void zoomMap(MogoLatLng latLng, Context context) {
+ try {
+ if (latLng == null) {
+ return;
+ }
+ //Logger.d(V2XConst.MODULE_NAME, "重新调整地图缩放比:" + latLng);
+
+ Rect mBoundRect = new Rect();
+ final int paddingTop;
+ final int paddingBottom;
+ final int paddingRight;
+ final int paddingLeft;
+ if (CarSeries.getSeries() == CarSeries.CAR_SERIES_F80X) {
+ paddingTop = WindowUtils.dip2px(context, 150);
+ paddingBottom = WindowUtils.dip2px(context, 100);
+ paddingRight = WindowUtils.dip2px(context, 100);
+ paddingLeft = WindowUtils.dip2px(context, 475);
+ } else {
+ paddingTop = WindowUtils.dip2px(context, 170);
+ paddingBottom = WindowUtils.dip2px(context, 100);
+ paddingRight = WindowUtils.dip2px(context, 100);
+ paddingLeft = WindowUtils.dip2px(context, 575);
+ }
+
+ mBoundRect.bottom = paddingBottom;
+ mBoundRect.top = paddingTop;
+ mBoundRect.left = paddingLeft;
+ mBoundRect.right = paddingRight;
+
+ // 当前车辆位置
+ MogoLatLng carLocation = V2XServiceManager.getNavi().getCarLocation();
+ // 调整自适应的地图镜头
+ V2XServiceManager.getMapUIController().showBounds(TAG,
+ carLocation,
+ Collections.singletonList(latLng),
+ mBoundRect,
+ true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 设置地图的缩放级别
+ *
+ * @param zoomScale 缩放级别
+ */
+ public static void resetMapZoom(float zoomScale) {
+ V2XServiceManager.getMapUIController().changeZoom(zoomScale);
+ // 锁车就是将地图视图移植中心点,因为行驶中的车和地图要相对的跟随
+ V2XServiceManager.getMapUIController().setLockZoom((int) zoomScale);
+ V2XServiceManager.getMapUIController().recoverLockMode();
+ }
+
+ /**
+ * 根据距离调整地图的缩放比例
+ *
+ * @param distance 距离
+ */
+ public static void changeMapZoomWithDistance(double distance) {
+ Logger.d(V2XConst.MODULE_NAME, "根据距离调整地图的缩放比例:" + distance);
+ if (distance <= 500 && distance > 400) {
+ resetMapZoom(15);
+ } else if (distance <= 400 && distance > 300) {
+ resetMapZoom(16);
+ } else if (distance <= 300 && distance > 200) {
+ resetMapZoom(16.5f);
+ } else if (distance <= 200 && distance > 100) {
+ resetMapZoom(17f);
+ } else if (distance <= 100 && distance >= 0) {
+ resetMapZoom(17.5f);
+ } else if (distance >= 500) {
+ resetMapZoom(12);
+ }
+ }
+
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/RoadConditionUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/RoadConditionUtils.java
new file mode 100644
index 0000000000..4302c9d997
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/RoadConditionUtils.java
@@ -0,0 +1,101 @@
+package com.mogo.module.v2x.utils;
+
+import android.content.Intent;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.V2XServiceManager;
+import com.mogo.module.common.entity.V2XPoiTypeEnum;
+import com.mogo.utils.logger.Logger;
+
+import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020/4/16 2:25 PM
+ * desc : 调用探路模块相关的工具
+ * version: 1.0
+ */
+public class RoadConditionUtils {
+ /**
+ * 向探路模块发送消息正确的确认广播
+ *
+ * @param poiType 当前poi信息
+ */
+ public static void sendShareReceiverInfo(String poiType) {
+ if (poiType != null) {
+ switch (poiType) {
+ case V2XPoiTypeEnum.FOURS_BLOCK_UP:
+ sendShareReceiver("1");
+ break;
+ case V2XPoiTypeEnum.TRAFFIC_CHECK:
+ sendShareReceiver("2");
+ break;
+ case V2XPoiTypeEnum.ROAD_CLOSED:
+ sendShareReceiver("3");
+ break;
+ }
+ }
+ }
+
+ /**
+ * 向探路模块发送数据纠错广播
+ *
+ * @param poiType 当前poi信息
+ */
+ public static void sendDataErrorReceiverInfo(String poiType, String infoId, String updateType) {
+ sendDataErrorReceiver(infoId, poiType, updateType);
+ }
+
+
+ /**
+ * 发送广播 type: 1拥堵,2交通检查,3封路
+ */
+ public static void sendShareReceiver(String type) {
+ Intent intent = new Intent();
+ intent.setAction("com.zhidao.roadcondition.share");
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ intent.putExtra("type", type);
+ V2XUtils.getApp().sendBroadcast(intent);
+ Logger.d(MODULE_NAME, "通过广播通知探路正确。。。");
+ }
+
+ /**
+ * 数据错误
+ *
+ * @param id 事件ID
+ * @param poiType 事件类型
+ */
+ public static void sendDataErrorReceiver(String id, String poiType, String updateType) {
+ showTip();
+
+ Intent intent = new Intent();
+ intent.setAction("com.zhidao.tanlu.dataerror");
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ intent.putExtra("id", id);
+ intent.putExtra("type", poiType);
+ intent.putExtra("updateType", updateType);
+ V2XUtils.getApp().sendBroadcast(intent);
+ Logger.d(MODULE_NAME, "通过广播通知探路纠错:id = " + id + " poiType = " + poiType + " updateType = " + updateType);
+ sendShareReceiverInfo(poiType);
+ }
+
+ /**
+ * 显示Toast
+ */
+ private static void showTip() {
+ AIAssist.getInstance(V2XUtils.getApp()).speakTTSVoice("已反馈", null);
+ ToastUtils.setGravity(Gravity.CENTER, 0, 0);
+ View toastView = LayoutInflater.from(V2XServiceManager.getContext()).inflate(R.layout.toast_view, null);
+ TextView msgView = toastView.findViewById(R.id.tvFeedbackContent);
+ msgView.setText("已反馈");
+ ToastUtils.showCustomShort(toastView);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/SpanUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/SpanUtils.java
new file mode 100644
index 0000000000..2159535918
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/SpanUtils.java
@@ -0,0 +1,1433 @@
+package com.mogo.module.v2x.utils;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import android.text.Layout;
+import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.AlignmentSpan;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.CharacterStyle;
+import android.text.style.ClickableSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.LineHeightSpan;
+import android.text.style.MaskFilterSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.ReplacementSpan;
+import android.text.style.ScaleXSpan;
+import android.text.style.StrikethroughSpan;
+import android.text.style.StyleSpan;
+import android.text.style.SubscriptSpan;
+import android.text.style.SuperscriptSpan;
+import android.text.style.TypefaceSpan;
+import android.text.style.URLSpan;
+import android.text.style.UnderlineSpan;
+import android.text.style.UpdateAppearance;
+import android.util.Log;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+
+import com.mogo.utils.logger.Logger;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+
+import static android.graphics.BlurMaskFilter.Blur;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 16/12/13
+ * desc : utils about span
+ *
+ */
+public final class SpanUtils {
+
+ private static final int COLOR_DEFAULT = 0xFEFFFFFF;
+
+ public static final int ALIGN_BOTTOM = 0;
+ public static final int ALIGN_BASELINE = 1;
+ public static final int ALIGN_CENTER = 2;
+ public static final int ALIGN_TOP = 3;
+
+ @IntDef({ALIGN_BOTTOM, ALIGN_BASELINE, ALIGN_CENTER, ALIGN_TOP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Align {
+ }
+
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ private TextView mTextView;
+ private CharSequence mText;
+ private int flag;
+ private int foregroundColor;
+ private int backgroundColor;
+ private int lineHeight;
+ private int alignLine;
+ private int quoteColor;
+ private int stripeWidth;
+ private int quoteGapWidth;
+ private int first;
+ private int rest;
+ private int bulletColor;
+ private int bulletRadius;
+ private int bulletGapWidth;
+ private int fontSize;
+ private boolean fontSizeIsDp;
+ private float proportion;
+ private float xProportion;
+ private boolean isStrikethrough;
+ private boolean isUnderline;
+ private boolean isSuperscript;
+ private boolean isSubscript;
+ private boolean isBold;
+ private boolean isItalic;
+ private boolean isBoldItalic;
+ private String fontFamily;
+ private Typeface typeface;
+ private Alignment alignment;
+ private int verticalAlign;
+ private ClickableSpan clickSpan;
+ private String url;
+ private float blurRadius;
+ private Blur style;
+ private Shader shader;
+ private float shadowRadius;
+ private float shadowDx;
+ private float shadowDy;
+ private int shadowColor;
+ private Object[] spans;
+
+ private Bitmap imageBitmap;
+ private Drawable imageDrawable;
+ private Uri imageUri;
+ private int imageResourceId;
+ private int alignImage;
+
+ private int spaceSize;
+ private int spaceColor;
+
+ private SerializableSpannableStringBuilder mBuilder;
+
+ private int mType;
+ private final int mTypeCharSequence = 0;
+ private final int mTypeImage = 1;
+ private final int mTypeSpace = 2;
+
+ private SpanUtils(TextView textView) {
+ this();
+ mTextView = textView;
+ }
+
+ public SpanUtils() {
+ mBuilder = new SerializableSpannableStringBuilder();
+ mText = "";
+ mType = -1;
+ setDefault();
+ }
+
+ private void setDefault() {
+ flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
+ foregroundColor = COLOR_DEFAULT;
+ backgroundColor = COLOR_DEFAULT;
+ lineHeight = -1;
+ quoteColor = COLOR_DEFAULT;
+ first = -1;
+ bulletColor = COLOR_DEFAULT;
+ fontSize = -1;
+ proportion = -1;
+ xProportion = -1;
+ isStrikethrough = false;
+ isUnderline = false;
+ isSuperscript = false;
+ isSubscript = false;
+ isBold = false;
+ isItalic = false;
+ isBoldItalic = false;
+ fontFamily = null;
+ typeface = null;
+ alignment = null;
+ verticalAlign = -1;
+ clickSpan = null;
+ url = null;
+ blurRadius = -1;
+ shader = null;
+ shadowRadius = -1;
+ spans = null;
+
+ imageBitmap = null;
+ imageDrawable = null;
+ imageUri = null;
+ imageResourceId = -1;
+
+ spaceSize = -1;
+ }
+
+ /**
+ * Set the span of flag.
+ *
+ * @param flag The flag.
+ *
+ * {@link Spanned#SPAN_INCLUSIVE_EXCLUSIVE}
+ * {@link Spanned#SPAN_INCLUSIVE_INCLUSIVE}
+ * {@link Spanned#SPAN_EXCLUSIVE_EXCLUSIVE}
+ * {@link Spanned#SPAN_EXCLUSIVE_INCLUSIVE}
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFlag(final int flag) {
+ this.flag = flag;
+ return this;
+ }
+
+ /**
+ * Set the span of foreground's color.
+ *
+ * @param color The color of foreground
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setForegroundColor(@ColorInt final int color) {
+ this.foregroundColor = color;
+ return this;
+ }
+
+ /**
+ * Set the span of background's color.
+ *
+ * @param color The color of background
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBackgroundColor(@ColorInt final int color) {
+ this.backgroundColor = color;
+ return this;
+ }
+
+ /**
+ * Set the span of line height.
+ *
+ * @param lineHeight The line height, in pixel.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setLineHeight(@IntRange(from = 0) final int lineHeight) {
+ return setLineHeight(lineHeight, ALIGN_CENTER);
+ }
+
+ /**
+ * Set the span of line height.
+ *
+ * @param lineHeight The line height, in pixel.
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER}
+ * {@link Align#ALIGN_BOTTOM}
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setLineHeight(@IntRange(from = 0) final int lineHeight,
+ @Align final int align) {
+ this.lineHeight = lineHeight;
+ this.alignLine = align;
+ return this;
+ }
+
+ /**
+ * Set the span of quote's color.
+ *
+ * @param color The color of quote
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setQuoteColor(@ColorInt final int color) {
+ return setQuoteColor(color, 2, 2);
+ }
+
+ /**
+ * Set the span of quote's color.
+ *
+ * @param color The color of quote.
+ * @param stripeWidth The width of stripe, in pixel.
+ * @param gapWidth The width of gap, in pixel.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setQuoteColor(@ColorInt final int color,
+ @IntRange(from = 1) final int stripeWidth,
+ @IntRange(from = 0) final int gapWidth) {
+ this.quoteColor = color;
+ this.stripeWidth = stripeWidth;
+ this.quoteGapWidth = gapWidth;
+ return this;
+ }
+
+ /**
+ * Set the span of leading margin.
+ *
+ * @param first The indent for the first line of the paragraph.
+ * @param rest The indent for the remaining lines of the paragraph.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setLeadingMargin(@IntRange(from = 0) final int first,
+ @IntRange(from = 0) final int rest) {
+ this.first = first;
+ this.rest = rest;
+ return this;
+ }
+
+ /**
+ * Set the span of bullet.
+ *
+ * @param gapWidth The width of gap, in pixel.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBullet(@IntRange(from = 0) final int gapWidth) {
+ return setBullet(0, 3, gapWidth);
+ }
+
+ /**
+ * Set the span of bullet.
+ *
+ * @param color The color of bullet.
+ * @param radius The radius of bullet, in pixel.
+ * @param gapWidth The width of gap, in pixel.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBullet(@ColorInt final int color,
+ @IntRange(from = 0) final int radius,
+ @IntRange(from = 0) final int gapWidth) {
+ this.bulletColor = color;
+ this.bulletRadius = radius;
+ this.bulletGapWidth = gapWidth;
+ return this;
+ }
+
+ /**
+ * Set the span of font's size.
+ *
+ * @param size The size of font.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFontSize(@IntRange(from = 0) final int size) {
+ return setFontSize(size, false);
+ }
+
+ /**
+ * Set the span of size of font.
+ *
+ * @param size The size of font.
+ * @param isSp True to use sp, false to use pixel.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFontSize(@IntRange(from = 0) final int size, final boolean isSp) {
+ this.fontSize = size;
+ this.fontSizeIsDp = isSp;
+ return this;
+ }
+
+ /**
+ * Set the span of proportion of font.
+ *
+ * @param proportion The proportion of font.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFontProportion(final float proportion) {
+ this.proportion = proportion;
+ return this;
+ }
+
+ /**
+ * Set the span of transverse proportion of font.
+ *
+ * @param proportion The transverse proportion of font.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFontXProportion(final float proportion) {
+ this.xProportion = proportion;
+ return this;
+ }
+
+ /**
+ * Set the span of strikethrough.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setStrikethrough() {
+ this.isStrikethrough = true;
+ return this;
+ }
+
+ /**
+ * Set the span of underline.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setUnderline() {
+ this.isUnderline = true;
+ return this;
+ }
+
+ /**
+ * Set the span of superscript.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setSuperscript() {
+ this.isSuperscript = true;
+ return this;
+ }
+
+ /**
+ * Set the span of subscript.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setSubscript() {
+ this.isSubscript = true;
+ return this;
+ }
+
+ /**
+ * Set the span of bold.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBold() {
+ isBold = true;
+ return this;
+ }
+
+ /**
+ * Set the span of italic.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setItalic() {
+ isItalic = true;
+ return this;
+ }
+
+ /**
+ * Set the span of bold italic.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBoldItalic() {
+ isBoldItalic = true;
+ return this;
+ }
+
+ /**
+ * Set the span of font family.
+ *
+ * @param fontFamily The font family.
+ *
+ * monospace
+ * serif
+ * sans-serif
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setFontFamily(@NonNull final String fontFamily) {
+ this.fontFamily = fontFamily;
+ return this;
+ }
+
+ /**
+ * Set the span of typeface.
+ *
+ * @param typeface The typeface.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setTypeface(@NonNull final Typeface typeface) {
+ this.typeface = typeface;
+ return this;
+ }
+
+ /**
+ * Set the span of horizontal alignment.
+ *
+ * @param alignment The alignment.
+ *
+ * {@link Alignment#ALIGN_NORMAL }
+ * {@link Alignment#ALIGN_OPPOSITE}
+ * {@link Alignment#ALIGN_CENTER }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setHorizontalAlign(@NonNull final Alignment alignment) {
+ this.alignment = alignment;
+ return this;
+ }
+
+ /**
+ * Set the span of vertical alignment.
+ *
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER }
+ * {@link Align#ALIGN_BASELINE}
+ * {@link Align#ALIGN_BOTTOM }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setVerticalAlign(@Align final int align) {
+ this.verticalAlign = align;
+ return this;
+ }
+
+ /**
+ * Set the span of click.
+ * Must set {@code view.setMovementMethod(LinkMovementMethod.getInstance())}
+ *
+ * @param clickSpan The span of click.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setClickSpan(@NonNull final ClickableSpan clickSpan) {
+ if (mTextView != null && mTextView.getMovementMethod() == null) {
+ mTextView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ this.clickSpan = clickSpan;
+ return this;
+ }
+
+ /**
+ * Set the span of url.
+ * Must set {@code view.setMovementMethod(LinkMovementMethod.getInstance())}
+ *
+ * @param url The url.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setUrl(@NonNull final String url) {
+ if (mTextView != null && mTextView.getMovementMethod() == null) {
+ mTextView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ this.url = url;
+ return this;
+ }
+
+ /**
+ * Set the span of blur.
+ *
+ * @param radius The radius of blur.
+ * @param style The style.
+ *
+ * {@link Blur#NORMAL}
+ * {@link Blur#SOLID}
+ * {@link Blur#OUTER}
+ * {@link Blur#INNER}
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setBlur(@FloatRange(from = 0, fromInclusive = false) final float radius,
+ final Blur style) {
+ this.blurRadius = radius;
+ this.style = style;
+ return this;
+ }
+
+ /**
+ * Set the span of shader.
+ *
+ * @param shader The shader.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setShader(@NonNull final Shader shader) {
+ this.shader = shader;
+ return this;
+ }
+
+ /**
+ * Set the span of shadow.
+ *
+ * @param radius The radius of shadow.
+ * @param dx X-axis offset, in pixel.
+ * @param dy Y-axis offset, in pixel.
+ * @param shadowColor The color of shadow.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setShadow(@FloatRange(from = 0, fromInclusive = false) final float radius,
+ final float dx,
+ final float dy,
+ final int shadowColor) {
+ this.shadowRadius = radius;
+ this.shadowDx = dx;
+ this.shadowDy = dy;
+ this.shadowColor = shadowColor;
+ return this;
+ }
+
+
+ /**
+ * Set the spans.
+ *
+ * @param spans The spans.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils setSpans(@NonNull final Object... spans) {
+ if (spans.length > 0) {
+ this.spans = spans;
+ }
+ return this;
+ }
+
+ /**
+ * Append the text text.
+ *
+ * @param text The text.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils append(@NonNull final CharSequence text) {
+ apply(mTypeCharSequence);
+ mText = text;
+ return this;
+ }
+
+ /**
+ * Append one line.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendLine() {
+ apply(mTypeCharSequence);
+ mText = LINE_SEPARATOR;
+ return this;
+ }
+
+ /**
+ * Append text and one line.
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendLine(@NonNull final CharSequence text) {
+ apply(mTypeCharSequence);
+ mText = text + LINE_SEPARATOR;
+ return this;
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param bitmap The bitmap of image.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Bitmap bitmap) {
+ return appendImage(bitmap, ALIGN_BOTTOM);
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param bitmap The bitmap.
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER }
+ * {@link Align#ALIGN_BASELINE}
+ * {@link Align#ALIGN_BOTTOM }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Bitmap bitmap, @Align final int align) {
+ apply(mTypeImage);
+ this.imageBitmap = bitmap;
+ this.alignImage = align;
+ return this;
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param drawable The drawable of image.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Drawable drawable) {
+ return appendImage(drawable, ALIGN_BOTTOM);
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param drawable The drawable of image.
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER }
+ * {@link Align#ALIGN_BASELINE}
+ * {@link Align#ALIGN_BOTTOM }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Drawable drawable, @Align final int align) {
+ apply(mTypeImage);
+ this.imageDrawable = drawable;
+ this.alignImage = align;
+ return this;
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param uri The uri of image.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Uri uri) {
+ return appendImage(uri, ALIGN_BOTTOM);
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param uri The uri of image.
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER }
+ * {@link Align#ALIGN_BASELINE}
+ * {@link Align#ALIGN_BOTTOM }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@NonNull final Uri uri, @Align final int align) {
+ apply(mTypeImage);
+ this.imageUri = uri;
+ this.alignImage = align;
+ return this;
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param resourceId The resource id of image.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@DrawableRes final int resourceId) {
+ return appendImage(resourceId, ALIGN_BOTTOM);
+ }
+
+ /**
+ * Append one image.
+ *
+ * @param resourceId The resource id of image.
+ * @param align The alignment.
+ *
+ * {@link Align#ALIGN_TOP }
+ * {@link Align#ALIGN_CENTER }
+ * {@link Align#ALIGN_BASELINE}
+ * {@link Align#ALIGN_BOTTOM }
+ *
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendImage(@DrawableRes final int resourceId, @Align final int align) {
+ apply(mTypeImage);
+ this.imageResourceId = resourceId;
+ this.alignImage = align;
+ return this;
+ }
+
+ /**
+ * Append space.
+ *
+ * @param size The size of space.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendSpace(@IntRange(from = 0) final int size) {
+ return appendSpace(size, Color.TRANSPARENT);
+ }
+
+ /**
+ * Append space.
+ *
+ * @param size The size of space.
+ * @param color The color of space.
+ * @return the single {@link SpanUtils} instance
+ */
+ public SpanUtils appendSpace(@IntRange(from = 0) final int size, @ColorInt final int color) {
+ apply(mTypeSpace);
+ spaceSize = size;
+ spaceColor = color;
+ return this;
+ }
+
+ private void apply(final int type) {
+ applyLast();
+ mType = type;
+ }
+
+ public SpannableStringBuilder get() {
+ return mBuilder;
+ }
+
+ /**
+ * Create the span string.
+ *
+ * @return the span string
+ */
+ public SpannableStringBuilder create() {
+ applyLast();
+ if (mTextView != null) {
+ mTextView.setText(mBuilder);
+ }
+ return mBuilder;
+ }
+
+ private void applyLast() {
+ if (mType == mTypeCharSequence) {
+ updateCharCharSequence();
+ } else if (mType == mTypeImage) {
+ updateImage();
+ } else if (mType == mTypeSpace) {
+ updateSpace();
+ }
+ setDefault();
+ }
+
+ private void updateCharCharSequence() {
+ if (mText.length() == 0) {
+ return;
+ }
+ int start = mBuilder.length();
+ if (start == 0 && lineHeight != -1) {// bug of LineHeightSpan when first line
+ mBuilder.append(Character.toString((char) 2))
+ .append("\n")
+ .setSpan(new AbsoluteSizeSpan(0), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ start = 2;
+ }
+ mBuilder.append(mText);
+ int end = mBuilder.length();
+ if (verticalAlign != -1) {
+ mBuilder.setSpan(new VerticalAlignSpan(verticalAlign), start, end, flag);
+ }
+ if (foregroundColor != COLOR_DEFAULT) {
+ mBuilder.setSpan(new ForegroundColorSpan(foregroundColor), start, end, flag);
+ }
+ if (backgroundColor != COLOR_DEFAULT) {
+ mBuilder.setSpan(new BackgroundColorSpan(backgroundColor), start, end, flag);
+ }
+ if (first != -1) {
+ mBuilder.setSpan(new LeadingMarginSpan.Standard(first, rest), start, end, flag);
+ }
+ if (quoteColor != COLOR_DEFAULT) {
+ mBuilder.setSpan(
+ new CustomQuoteSpan(quoteColor, stripeWidth, quoteGapWidth),
+ start,
+ end,
+ flag
+ );
+ }
+ if (bulletColor != COLOR_DEFAULT) {
+ mBuilder.setSpan(
+ new CustomBulletSpan(bulletColor, bulletRadius, bulletGapWidth),
+ start,
+ end,
+ flag
+ );
+ }
+ if (fontSize != -1) {
+ mBuilder.setSpan(new AbsoluteSizeSpan(fontSize, fontSizeIsDp), start, end, flag);
+ }
+ if (proportion != -1) {
+ mBuilder.setSpan(new RelativeSizeSpan(proportion), start, end, flag);
+ }
+ if (xProportion != -1) {
+ mBuilder.setSpan(new ScaleXSpan(xProportion), start, end, flag);
+ }
+ if (lineHeight != -1) {
+ mBuilder.setSpan(new CustomLineHeightSpan(lineHeight, alignLine), start, end, flag);
+ }
+ if (isStrikethrough) {
+ mBuilder.setSpan(new StrikethroughSpan(), start, end, flag);
+ }
+ if (isUnderline) {
+ mBuilder.setSpan(new UnderlineSpan(), start, end, flag);
+ }
+ if (isSuperscript) {
+ mBuilder.setSpan(new SuperscriptSpan(), start, end, flag);
+ }
+ if (isSubscript) {
+ mBuilder.setSpan(new SubscriptSpan(), start, end, flag);
+ }
+ if (isBold) {
+ mBuilder.setSpan(new StyleSpan(Typeface.BOLD), start, end, flag);
+ }
+ if (isItalic) {
+ mBuilder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, flag);
+ }
+ if (isBoldItalic) {
+ mBuilder.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, flag);
+ }
+ if (fontFamily != null) {
+ mBuilder.setSpan(new TypefaceSpan(fontFamily), start, end, flag);
+ }
+ if (typeface != null) {
+ mBuilder.setSpan(new CustomTypefaceSpan(typeface), start, end, flag);
+ }
+ if (alignment != null) {
+ mBuilder.setSpan(new AlignmentSpan.Standard(alignment), start, end, flag);
+ }
+ if (clickSpan != null) {
+ mBuilder.setSpan(clickSpan, start, end, flag);
+ }
+ if (url != null) {
+ mBuilder.setSpan(new URLSpan(url), start, end, flag);
+ }
+ if (blurRadius != -1) {
+ mBuilder.setSpan(
+ new MaskFilterSpan(new BlurMaskFilter(blurRadius, style)),
+ start,
+ end,
+ flag
+ );
+ }
+ if (shader != null) {
+ mBuilder.setSpan(new ShaderSpan(shader), start, end, flag);
+ }
+ if (shadowRadius != -1) {
+ mBuilder.setSpan(
+ new ShadowSpan(shadowRadius, shadowDx, shadowDy, shadowColor),
+ start,
+ end,
+ flag
+ );
+ }
+ if (spans != null) {
+ for (Object span : spans) {
+ mBuilder.setSpan(span, start, end, flag);
+ }
+ }
+ }
+
+ private void updateImage() {
+ int start = mBuilder.length();
+ mText = " ";
+ updateCharCharSequence();
+ int end = mBuilder.length();
+ if (imageBitmap != null) {
+ mBuilder.setSpan(new CustomImageSpan(imageBitmap, alignImage), start, end, flag);
+ } else if (imageDrawable != null) {
+ mBuilder.setSpan(new CustomImageSpan(imageDrawable, alignImage), start, end, flag);
+ } else if (imageUri != null) {
+ mBuilder.setSpan(new CustomImageSpan(imageUri, alignImage), start, end, flag);
+ } else if (imageResourceId != -1) {
+ mBuilder.setSpan(new CustomImageSpan(imageResourceId, alignImage), start, end, flag);
+ }
+ }
+
+ private void updateSpace() {
+ int start = mBuilder.length();
+ mText = "< >";
+ updateCharCharSequence();
+ int end = mBuilder.length();
+ mBuilder.setSpan(new SpaceSpan(spaceSize, spaceColor), start, end, flag);
+ }
+
+ static class VerticalAlignSpan extends ReplacementSpan {
+
+ static final int ALIGN_CENTER = 2;
+ static final int ALIGN_TOP = 3;
+
+ final int mVerticalAlignment;
+
+ VerticalAlignSpan(int verticalAlignment) {
+ mVerticalAlignment = verticalAlignment;
+ }
+
+ @Override
+ public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
+ text = text.subSequence(start, end);
+ return (int) paint.measureText(text.toString());
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
+ text = text.subSequence(start, end);
+ Paint.FontMetricsInt fm = paint.getFontMetricsInt();
+// int need = height - (v + fm.descent - fm.ascent - spanstartv);
+// if (need > 0) {
+// if (mVerticalAlignment == ALIGN_TOP) {
+// fm.descent += need;
+// } else if (mVerticalAlignment == ALIGN_CENTER) {
+// fm.descent += need / 2;
+// fm.ascent -= need / 2;
+// } else {
+// fm.ascent -= need;
+// }
+// }
+// need = height - (v + fm.bottom - fm.top - spanstartv);
+// if (need > 0) {
+// if (mVerticalAlignment == ALIGN_TOP) {
+// fm.bottom += need;
+// } else if (mVerticalAlignment == ALIGN_CENTER) {
+// fm.bottom += need / 2;
+// fm.top -= need / 2;
+// } else {
+// fm.top -= need;
+// }
+// }
+
+ canvas.drawText(text.toString(), x, y - ((y + fm.descent + y + fm.ascent) / 2 - (bottom + top) / 2), paint);
+ }
+ }
+
+ static class CustomLineHeightSpan implements LineHeightSpan {
+
+ private final int height;
+
+ static final int ALIGN_CENTER = 2;
+ static final int ALIGN_TOP = 3;
+
+ final int mVerticalAlignment;
+ static Paint.FontMetricsInt sfm;
+
+ CustomLineHeightSpan(int height, int verticalAlignment) {
+ this.height = height;
+ mVerticalAlignment = verticalAlignment;
+ }
+
+ @Override
+ public void chooseHeight(final CharSequence text, final int start, final int end,
+ final int spanstartv, final int v, final Paint.FontMetricsInt fm) {
+ if (sfm == null) {
+ sfm = new Paint.FontMetricsInt();
+ sfm.top = fm.top;
+ sfm.ascent = fm.ascent;
+ sfm.descent = fm.descent;
+ sfm.bottom = fm.bottom;
+ sfm.leading = fm.leading;
+ } else {
+ fm.top = sfm.top;
+ fm.ascent = sfm.ascent;
+ fm.descent = sfm.descent;
+ fm.bottom = sfm.bottom;
+ fm.leading = sfm.leading;
+ }
+ int need = height - (v + fm.descent - fm.ascent - spanstartv);
+ if (need > 0) {
+ if (mVerticalAlignment == ALIGN_TOP) {
+ fm.descent += need;
+ } else if (mVerticalAlignment == ALIGN_CENTER) {
+ fm.descent += need / 2;
+ fm.ascent -= need / 2;
+ } else {
+ fm.ascent -= need;
+ }
+ }
+ need = height - (v + fm.bottom - fm.top - spanstartv);
+ if (need > 0) {
+ if (mVerticalAlignment == ALIGN_TOP) {
+ fm.bottom += need;
+ } else if (mVerticalAlignment == ALIGN_CENTER) {
+ fm.bottom += need / 2;
+ fm.top -= need / 2;
+ } else {
+ fm.top -= need;
+ }
+ }
+ if (end == ((Spanned) text).getSpanEnd(this)) {
+ sfm = null;
+ }
+ }
+ }
+
+ static class SpaceSpan extends ReplacementSpan {
+
+ private final int width;
+ private final Paint paint = new Paint();
+
+ private SpaceSpan(final int width) {
+ this(width, Color.TRANSPARENT);
+ }
+
+ private SpaceSpan(final int width, final int color) {
+ super();
+ this.width = width;
+ paint.setColor(color);
+ paint.setStyle(Paint.Style.FILL);
+ }
+
+ @Override
+ public int getSize(@NonNull final Paint paint, final CharSequence text,
+ @IntRange(from = 0) final int start,
+ @IntRange(from = 0) final int end,
+ @Nullable final Paint.FontMetricsInt fm) {
+ return width;
+ }
+
+ @Override
+ public void draw(@NonNull final Canvas canvas, final CharSequence text,
+ @IntRange(from = 0) final int start,
+ @IntRange(from = 0) final int end,
+ final float x, final int top, final int y, final int bottom,
+ @NonNull final Paint paint) {
+ canvas.drawRect(x, top, x + width, bottom, this.paint);
+ }
+ }
+
+ static class CustomQuoteSpan implements LeadingMarginSpan {
+
+ private final int color;
+ private final int stripeWidth;
+ private final int gapWidth;
+
+ private CustomQuoteSpan(final int color, final int stripeWidth, final int gapWidth) {
+ super();
+ this.color = color;
+ this.stripeWidth = stripeWidth;
+ this.gapWidth = gapWidth;
+ }
+
+ @Override
+ public int getLeadingMargin(final boolean first) {
+ return stripeWidth + gapWidth;
+ }
+
+ @Override
+ public void drawLeadingMargin(final Canvas c, final Paint p, final int x, final int dir,
+ final int top, final int baseline, final int bottom,
+ final CharSequence text, final int start, final int end,
+ final boolean first, final Layout layout) {
+ Paint.Style style = p.getStyle();
+ int color = p.getColor();
+
+ p.setStyle(Paint.Style.FILL);
+ p.setColor(this.color);
+
+ c.drawRect(x, top, x + dir * stripeWidth, bottom, p);
+
+ p.setStyle(style);
+ p.setColor(color);
+ }
+ }
+
+ static class CustomBulletSpan implements LeadingMarginSpan {
+
+ private final int color;
+ private final int radius;
+ private final int gapWidth;
+
+ private Path sBulletPath = null;
+
+ private CustomBulletSpan(final int color, final int radius, final int gapWidth) {
+ this.color = color;
+ this.radius = radius;
+ this.gapWidth = gapWidth;
+ }
+
+ @Override
+ public int getLeadingMargin(final boolean first) {
+ return 2 * radius + gapWidth;
+ }
+
+ @Override
+ public void drawLeadingMargin(final Canvas c, final Paint p, final int x, final int dir,
+ final int top, final int baseline, final int bottom,
+ final CharSequence text, final int start, final int end,
+ final boolean first, final Layout l) {
+ if (((Spanned) text).getSpanStart(this) == start) {
+ Paint.Style style = p.getStyle();
+ int oldColor = 0;
+ oldColor = p.getColor();
+ p.setColor(color);
+ p.setStyle(Paint.Style.FILL);
+ if (c.isHardwareAccelerated()) {
+ if (sBulletPath == null) {
+ sBulletPath = new Path();
+ // Bullet is slightly better to avoid aliasing artifacts on mdpi devices.
+ sBulletPath.addCircle(0.0f, 0.0f, radius, Path.Direction.CW);
+ }
+ c.save();
+ c.translate(x + dir * radius, (top + bottom) / 2.0f);
+ c.drawPath(sBulletPath, p);
+ c.restore();
+ } else {
+ c.drawCircle(x + dir * radius, (top + bottom) / 2.0f, radius, p);
+ }
+ p.setColor(oldColor);
+ p.setStyle(style);
+ }
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ static class CustomTypefaceSpan extends TypefaceSpan {
+
+ private final Typeface newType;
+
+ private CustomTypefaceSpan(final Typeface type) {
+ super("");
+ newType = type;
+ }
+
+ @Override
+ public void updateDrawState(final TextPaint textPaint) {
+ apply(textPaint, newType);
+ }
+
+ @Override
+ public void updateMeasureState(final TextPaint paint) {
+ apply(paint, newType);
+ }
+
+ private void apply(final Paint paint, final Typeface tf) {
+ int oldStyle;
+ Typeface old = paint.getTypeface();
+ if (old == null) {
+ oldStyle = 0;
+ } else {
+ oldStyle = old.getStyle();
+ }
+
+ int fake = oldStyle & ~tf.getStyle();
+ if ((fake & Typeface.BOLD) != 0) {
+ paint.setFakeBoldText(true);
+ }
+
+ if ((fake & Typeface.ITALIC) != 0) {
+ paint.setTextSkewX(-0.25f);
+ }
+
+ paint.getShader();
+
+ paint.setTypeface(tf);
+ }
+ }
+
+ static class CustomImageSpan extends CustomDynamicDrawableSpan {
+ private Drawable mDrawable;
+ private Uri mContentUri;
+ private int mResourceId;
+
+ private CustomImageSpan(final Bitmap b, final int verticalAlignment) {
+ super(verticalAlignment);
+ mDrawable = new BitmapDrawable(V2XUtils.getApp().getResources(), b);
+ mDrawable.setBounds(
+ 0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()
+ );
+ }
+
+ private CustomImageSpan(final Drawable d, final int verticalAlignment) {
+ super(verticalAlignment);
+ mDrawable = d;
+ mDrawable.setBounds(
+ 0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()
+ );
+ }
+
+ private CustomImageSpan(final Uri uri, final int verticalAlignment) {
+ super(verticalAlignment);
+ mContentUri = uri;
+ }
+
+ private CustomImageSpan(@DrawableRes final int resourceId, final int verticalAlignment) {
+ super(verticalAlignment);
+ mResourceId = resourceId;
+ }
+
+ @Override
+ public Drawable getDrawable() {
+ Drawable drawable = null;
+ if (mDrawable != null) {
+ drawable = mDrawable;
+ } else if (mContentUri != null) {
+ Bitmap bitmap;
+ try {
+ InputStream is =
+ V2XUtils.getApp().getContentResolver().openInputStream(mContentUri);
+ bitmap = BitmapFactory.decodeStream(is);
+ drawable = new BitmapDrawable(V2XUtils.getApp().getResources(), bitmap);
+ drawable.setBounds(
+ 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()
+ );
+ if (is != null) {
+ is.close();
+ }
+ } catch (Exception e) {
+ Log.e("sms", "Failed to loaded content " + mContentUri, e);
+ }
+ } else {
+ try {
+ drawable = ContextCompat.getDrawable(V2XUtils.getApp(), mResourceId);
+ drawable.setBounds(
+ 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()
+ );
+ } catch (Exception e) {
+ Log.e("sms", "Unable to find resource: " + mResourceId);
+ }
+ }
+ return drawable;
+ }
+ }
+
+ static abstract class CustomDynamicDrawableSpan extends ReplacementSpan {
+
+ static final int ALIGN_BOTTOM = 0;
+
+ static final int ALIGN_BASELINE = 1;
+
+ static final int ALIGN_CENTER = 2;
+
+ static final int ALIGN_TOP = 3;
+
+ final int mVerticalAlignment;
+
+ private CustomDynamicDrawableSpan() {
+ mVerticalAlignment = ALIGN_BOTTOM;
+ }
+
+ private CustomDynamicDrawableSpan(final int verticalAlignment) {
+ mVerticalAlignment = verticalAlignment;
+ }
+
+ public abstract Drawable getDrawable();
+
+ @Override
+ public int getSize(@NonNull final Paint paint, final CharSequence text,
+ final int start, final int end, final Paint.FontMetricsInt fm) {
+ Drawable d = getCachedDrawable();
+ Rect rect = d.getBounds();
+ if (fm != null) {
+// LogUtils.d("fm.top: " + fm.top,
+// "fm.ascent: " + fm.ascent,
+// "fm.descent: " + fm.descent,
+// "fm.bottom: " + fm.bottom,
+// "lineHeight: " + (fm.bottom - fm.top));
+ int lineHeight = fm.bottom - fm.top;
+ if (lineHeight < rect.height()) {
+ if (mVerticalAlignment == ALIGN_TOP) {
+ fm.top = fm.top;
+ fm.bottom = rect.height() + fm.top;
+ } else if (mVerticalAlignment == ALIGN_CENTER) {
+ fm.top = -rect.height() / 2 - lineHeight / 4;
+ fm.bottom = rect.height() / 2 - lineHeight / 4;
+ } else {
+ fm.top = -rect.height() + fm.bottom;
+ fm.bottom = fm.bottom;
+ }
+ fm.ascent = fm.top;
+ fm.descent = fm.bottom;
+ }
+ }
+ return rect.right;
+ }
+
+ @Override
+ public void draw(@NonNull final Canvas canvas, final CharSequence text,
+ final int start, final int end, final float x,
+ final int top, final int y, final int bottom, @NonNull final Paint paint) {
+ Drawable d = getCachedDrawable();
+ Rect rect = d.getBounds();
+ canvas.save();
+ float transY;
+ int lineHeight = bottom - top;
+// LogUtils.d("rectHeight: " + rect.height(),
+// "lineHeight: " + (bottom - top));
+ if (rect.height() < lineHeight) {
+ if (mVerticalAlignment == ALIGN_TOP) {
+ transY = top;
+ } else if (mVerticalAlignment == ALIGN_CENTER) {
+ transY = (bottom + top - rect.height()) / 2;
+ } else if (mVerticalAlignment == ALIGN_BASELINE) {
+ transY = y - rect.height();
+ } else {
+ transY = bottom - rect.height();
+ }
+ canvas.translate(x, transY);
+ } else {
+ canvas.translate(x, top);
+ }
+ d.draw(canvas);
+ canvas.restore();
+ }
+
+ private Drawable getCachedDrawable() {
+ WeakReference wr = mDrawableRef;
+ Drawable d = null;
+ if (wr != null) {
+ d = wr.get();
+ }
+ if (d == null) {
+ d = getDrawable();
+ mDrawableRef = new WeakReference<>(d);
+ }
+ return d;
+ }
+
+ private WeakReference mDrawableRef;
+ }
+
+ static class ShaderSpan extends CharacterStyle implements UpdateAppearance {
+ private Shader mShader;
+
+ private ShaderSpan(final Shader shader) {
+ this.mShader = shader;
+ }
+
+ @Override
+ public void updateDrawState(final TextPaint tp) {
+ tp.setShader(mShader);
+ }
+ }
+
+ static class ShadowSpan extends CharacterStyle implements UpdateAppearance {
+ private float radius;
+ private float dx, dy;
+ private int shadowColor;
+
+ private ShadowSpan(final float radius,
+ final float dx,
+ final float dy,
+ final int shadowColor) {
+ this.radius = radius;
+ this.dx = dx;
+ this.dy = dy;
+ this.shadowColor = shadowColor;
+ }
+
+ @Override
+ public void updateDrawState(final TextPaint tp) {
+ tp.setShadowLayer(radius, dx, dy, shadowColor);
+ }
+ }
+
+ private static class SerializableSpannableStringBuilder extends SpannableStringBuilder
+ implements Serializable {
+
+ private static final long serialVersionUID = 4909567650765875771L;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // static
+ ///////////////////////////////////////////////////////////////////////////
+
+ public static SpanUtils with(final TextView textView) {
+ return new SpanUtils(textView);
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/TestOnLineCarUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/TestOnLineCarUtils.java
new file mode 100644
index 0000000000..75f5490c78
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/TestOnLineCarUtils.java
@@ -0,0 +1,225 @@
+package com.mogo.module.v2x.utils;
+
+import com.mogo.module.common.entity.MarkerExploreWay;
+import com.mogo.module.common.entity.MarkerResponse;
+import com.mogo.module.v2x.R;
+import com.mogo.module.v2x.entity.net.V2XSpecialCarRes;
+import com.mogo.module.common.entity.V2XMessageEntity;
+import com.mogo.module.common.entity.V2XPushMessageEntity;
+import com.mogo.module.common.entity.V2XRoadEventEntity;
+import com.mogo.utils.network.utils.GsonUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * author : donghongyu
+ * e-mail : 1358506549@qq.com
+ * date : 2020-01-0918:20
+ * desc : 生成测试数据
+ * version: 1.0
+ */
+public class TestOnLineCarUtils {
+
+
+ /**
+ * 获取测试的违章停车数据
+ */
+ public static V2XMessageEntity> getV2XIllegalParkData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp().getResources().openRawResource(R.raw.illegal_park_data);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ MarkerResponse markerResponse = GsonUtil.objectFromJson(baos.toString(), MarkerResponse.class);
+
+ V2XMessageEntity> v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ILLEGAL_PARK_WARNING);
+ // 设置数据
+ v2xMessageEntity.setContent(markerResponse.getResult().getExploreWay());
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * 模拟道路事件测试数据
+ */
+ public static V2XMessageEntity getV2XScenarioRoadEventData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp()
+ .getResources()
+ .openRawResource(R.raw.scenario_road_event_data);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ V2XRoadEventEntity v2xRoadEventEntity = GsonUtil.objectFromJson(baos.toString(), V2XRoadEventEntity.class);
+
+ V2XMessageEntity v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING);
+ // 设置数据
+ v2xMessageEntity.setContent(v2xRoadEventEntity);
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 模拟H5推送数据
+ */
+ public static V2XMessageEntity getV2XScenarioPushEventData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp()
+ .getResources()
+ .openRawResource(R.raw.scenario_push_event_data);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ V2XPushMessageEntity v2xRoadEventEntity = GsonUtil.objectFromJson(baos.toString(), V2XPushMessageEntity.class);
+
+ V2XMessageEntity v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_WINDOW_WARNING);
+ // 设置数据
+ v2xMessageEntity.setContent(v2xRoadEventEntity);
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 模拟H5推送场景动画数据
+ */
+ public static V2XMessageEntity getV2XScenarioAnimationEventData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp()
+ .getResources()
+ .openRawResource(R.raw.scenario_push_animation_event_data);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ V2XPushMessageEntity v2xRoadEventEntity = GsonUtil.objectFromJson(baos.toString(), V2XPushMessageEntity.class);
+
+ V2XMessageEntity v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ANIMATION_WARNING);
+ // 设置数据
+ v2xMessageEntity.setContent(v2xRoadEventEntity);
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 模拟 疲劳驾驶
+ */
+ public static V2XMessageEntity getV2XScenarioFatigueDrivingData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp()
+ .getResources()
+ .openRawResource(R.raw.scenario_fatigue_driving_data);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ V2XPushMessageEntity v2xRoadEventEntity =
+ GsonUtil.objectFromJson(baos.toString(), V2XPushMessageEntity.class);
+
+ V2XMessageEntity v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_FATIGUE_DRIVING);
+ // 设置数据
+ v2xMessageEntity.setContent(v2xRoadEventEntity);
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 模拟 疲劳驾驶
+ */
+ public static V2XMessageEntity> getV2XScenarioSeekHelpData() {
+ try {
+ InputStream inputStream = V2XUtils.getApp()
+ .getResources()
+ .openRawResource(R.raw.scenario_seek_help);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = -1;
+ byte[] buffer = new byte[1024];
+ while ((len = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, len);
+ }
+ inputStream.close();
+
+ // 加载数据源
+ V2XSpecialCarRes v2xRoadEventEntity =
+ GsonUtil.objectFromJson(baos.toString(), V2XSpecialCarRes.class);
+
+ V2XMessageEntity> v2xMessageEntity = new V2XMessageEntity<>();
+ // 控制类型
+ v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_SEEK_WARNING);
+ // 设置数据
+ v2xMessageEntity.setContent(v2xRoadEventEntity.getCoordinates());
+ // 控制展示状态
+ v2xMessageEntity.setShowState(true);
+ return v2xMessageEntity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ThreadUtils.java b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ThreadUtils.java
new file mode 100644
index 0000000000..18ea02e1c8
--- /dev/null
+++ b/modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/utils/ThreadUtils.java
@@ -0,0 +1,1338 @@
+package com.mogo.module.v2x.utils;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ */
+public final class ThreadUtils {
+
+ private static final Map> TYPE_PRIORITY_POOLS = new HashMap<>();
+
+ private static final Map TASK_TASKINFO_MAP = new ConcurrentHashMap<>();
+
+ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+ private static final Timer TIMER = new Timer();
+
+ private static final byte TYPE_SINGLE = -1;
+ private static final byte TYPE_CACHED = -2;
+ private static final byte TYPE_IO = -4;
+ private static final byte TYPE_CPU = -8;
+
+ private static Executor sDeliver;
+
+ /**
+ * Return whether the thread is the main thread.
+ *
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
+
+ public static void runOnUiThread(final Runnable runnable) {
+ V2XUtils.runOnUiThread(runnable);
+ }
+
+ public static void runOnUiThreadDelayed(final Runnable runnable, long delayMillis) {
+ V2XUtils.runOnUiThreadDelayed(runnable, delayMillis);
+ }
+
+ /**
+ * Return a thread pool that reuses a fixed number of threads
+ * operating off a shared unbounded queue, using the provided
+ * ThreadFactory to create new threads when needed.
+ *
+ * @param size The size of thread in the pool.
+ * @return a fixed thread pool
+ */
+ public static ExecutorService getFixedPool(@IntRange(from = 1) final int size) {
+ return getPoolByTypeAndPriority(size);
+ }
+
+ /**
+ * Return a thread pool that reuses a fixed number of threads
+ * operating off a shared unbounded queue, using the provided
+ * ThreadFactory to create new threads when needed.
+ *
+ * @param size The size of thread in the pool.
+ * @param priority The priority of thread in the poll.
+ * @return a fixed thread pool
+ */
+ public static ExecutorService getFixedPool(@IntRange(from = 1) final int size,
+ @IntRange(from = 1, to = 10) final int priority) {
+ return getPoolByTypeAndPriority(size, priority);
+ }
+
+ /**
+ * Return a thread pool that uses a single worker thread operating
+ * off an unbounded queue, and uses the provided ThreadFactory to
+ * create a new thread when needed.
+ *
+ * @return a single thread pool
+ */
+ public static ExecutorService getSinglePool() {
+ return getPoolByTypeAndPriority(TYPE_SINGLE);
+ }
+
+ /**
+ * Return a thread pool that uses a single worker thread operating
+ * off an unbounded queue, and uses the provided ThreadFactory to
+ * create a new thread when needed.
+ *
+ * @param priority The priority of thread in the poll.
+ * @return a single thread pool
+ */
+ public static ExecutorService getSinglePool(@IntRange(from = 1, to = 10) final int priority) {
+ return getPoolByTypeAndPriority(TYPE_SINGLE, priority);
+ }
+
+ /**
+ * Return a thread pool that creates new threads as needed, but
+ * will reuse previously constructed threads when they are
+ * available.
+ *
+ * @return a cached thread pool
+ */
+ public static ExecutorService getCachedPool() {
+ return getPoolByTypeAndPriority(TYPE_CACHED);
+ }
+
+ /**
+ * Return a thread pool that creates new threads as needed, but
+ * will reuse previously constructed threads when they are
+ * available.
+ *
+ * @param priority The priority of thread in the poll.
+ * @return a cached thread pool
+ */
+ public static ExecutorService getCachedPool(@IntRange(from = 1, to = 10) final int priority) {
+ return getPoolByTypeAndPriority(TYPE_CACHED, priority);
+ }
+
+ /**
+ * Return a thread pool that creates (2 * CPU_COUNT + 1) threads
+ * operating off a queue which size is 128.
+ *
+ * @return a IO thread pool
+ */
+ public static ExecutorService getIoPool() {
+ return getPoolByTypeAndPriority(TYPE_IO);
+ }
+
+ /**
+ * Return a thread pool that creates (2 * CPU_COUNT + 1) threads
+ * operating off a queue which size is 128.
+ *
+ * @param priority The priority of thread in the poll.
+ * @return a IO thread pool
+ */
+ public static ExecutorService getIoPool(@IntRange(from = 1, to = 10) final int priority) {
+ return getPoolByTypeAndPriority(TYPE_IO, priority);
+ }
+
+ /**
+ * Return a thread pool that creates (CPU_COUNT + 1) threads
+ * operating off a queue which size is 128 and the maximum
+ * number of threads equals (2 * CPU_COUNT + 1).
+ *
+ * @return a cpu thread pool for
+ */
+ public static ExecutorService getCpuPool() {
+ return getPoolByTypeAndPriority(TYPE_CPU);
+ }
+
+ /**
+ * Return a thread pool that creates (CPU_COUNT + 1) threads
+ * operating off a queue which size is 128 and the maximum
+ * number of threads equals (2 * CPU_COUNT + 1).
+ *
+ * @param priority The priority of thread in the poll.
+ * @return a cpu thread pool for
+ */
+ public static ExecutorService getCpuPool(@IntRange(from = 1, to = 10) final int priority) {
+ return getPoolByTypeAndPriority(TYPE_CPU, priority);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixed(@IntRange(from = 1) final int size, final Task task) {
+ execute(getPoolByTypeAndPriority(size), task);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param priority The priority of thread in the poll.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixed(@IntRange(from = 1) final int size,
+ final Task task,
+ @IntRange(from = 1, to = 10) final int priority) {
+ execute(getPoolByTypeAndPriority(size, priority), task);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool after the given delay.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param delay The time from now to delay execution.
+ * @param unit The time unit of the delay parameter.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixedWithDelay(@IntRange(from = 1) final int size,
+ final Task task,
+ final long delay,
+ final TimeUnit unit) {
+ executeWithDelay(getPoolByTypeAndPriority(size), task, delay, unit);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool after the given delay.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param delay The time from now to delay execution.
+ * @param unit The time unit of the delay parameter.
+ * @param priority The priority of thread in the poll.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixedWithDelay(@IntRange(from = 1) final int size,
+ final Task task,
+ final long delay,
+ final TimeUnit unit,
+ @IntRange(from = 1, to = 10) final int priority) {
+ executeWithDelay(getPoolByTypeAndPriority(size, priority), task, delay, unit);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool at fix rate.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param period The period between successive executions.
+ * @param unit The time unit of the period parameter.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
+ final Task task,
+ final long period,
+ final TimeUnit unit) {
+ executeAtFixedRate(getPoolByTypeAndPriority(size), task, 0, period, unit);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool at fix rate.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param period The period between successive executions.
+ * @param unit The time unit of the period parameter.
+ * @param priority The priority of thread in the poll.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
+ final Task task,
+ final long period,
+ final TimeUnit unit,
+ @IntRange(from = 1, to = 10) final int priority) {
+ executeAtFixedRate(getPoolByTypeAndPriority(size, priority), task, 0, period, unit);
+ }
+
+ /**
+ * Executes the given task in a fixed thread pool at fix rate.
+ *
+ * @param size The size of thread in the fixed thread pool.
+ * @param task The task to execute.
+ * @param initialDelay The time to delay first execution.
+ * @param period The period between successive executions.
+ * @param unit The time unit of the initialDelay and period parameters.
+ * @param The type of the task's result.
+ */
+ public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
+ final Task