diff --git a/ZD_README/README_VersionHistory.md b/ZD_README/README_VersionHistory.md
index 56f59fab4a..aa6e59dedd 100644
--- a/ZD_README/README_VersionHistory.md
+++ b/ZD_README/README_VersionHistory.md
@@ -57,9 +57,6 @@ mogoservice : "com.mogo.service:mogo-service:${MOGO_COMMONS_VER
mogoserviceapi : "com.mogo.service:mogo-service-api:${MOGO_COMMONS_VERSION}",
moduleapps : "com.mogo.module:module-apps:${MOGO_COMMONS_VERSION}",
moduleextensions : "com.mogo.module:module-extensions:${MOGO_COMMONS_VERSION}",
-chat : "com.mogo.module.carchatout:module-chat:${MOGO_COMMONS_VERSION}",
-callchat : "com.mogo.module.carchatout:module-carchatting:${MOGO_COMMONS_VERSION}",
-callchatprovider : "com.mogo.module.carchatout:module-carchatting-provider:${MOGO_COMMONS_VERSION}",
// V2X
moduleV2x : "com.mogo.module:module-v2x:${MOGO_COMMONS_VERSION}",
diff --git a/app/build.gradle b/app/build.gradle
index a0c72dcba9..cd627761b2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -220,7 +220,7 @@ repositories {
}
aspectjx {
- include "com.mogo.chat"
+ include "com.mogo.eagle.core.function.chat"
}
diff --git a/build.gradle b/build.gradle
index 8da9516e51..7091777dfd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -115,3 +115,20 @@ afterEvaluate {
}
}
}
+
+subprojects.each {
+ Class> kotlinCompile = null
+ try {
+ kotlinCompile = Class.forName("org.jetbrains.kotlin.gradle.tasks.KotlinCompile")
+ } catch (Throwable t) {
+ t.printStackTrace()
+ }
+ if (kotlinCompile != null) {
+ it.tasks.withType(kotlinCompile).configureEach {
+ kotlinOptions {
+ jvmTarget = '1.8'
+ freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/config.gradle b/config.gradle
index 6a3e76a787..f99a5852dc 100644
--- a/config.gradle
+++ b/config.gradle
@@ -127,6 +127,7 @@ ext {
// androidx-lifecycle-process
androidxlifecycleprocess : "androidx.lifecycle:lifecycle-process:2.4.0",
+ androidxlifecycleservice : "androidx.lifecycle:lifecycle-service:2.4.0",
// rxjava2 with room
roomRxjava : 'androidx.room:room-rxjava2:2.2.3',
circleimageview : "de.hdodenhof:circleimageview:3.0.1",
diff --git a/core/function-impl/mogo-core-function-chat/.gitignore b/core/function-impl/mogo-core-function-chat/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-chat/build.gradle b/core/function-impl/mogo-core-function-chat/build.gradle
new file mode 100644
index 0000000000..b016d5a2a4
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/build.gradle
@@ -0,0 +1,82 @@
+plugins {
+ id 'com.android.library'
+ id 'kotlin-android'
+ id 'kotlin-android-extensions'
+ id 'kotlin-kapt'
+ id 'com.alibaba.arouter'
+}
+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'
+ //ARouter apt 参数
+ kapt {
+ useBuildCache = false
+ arguments {
+ arg("AROUTER_MODULE_NAME", project.getName())
+ }
+ }
+
+ ndk {
+ abiFilters "armeabi-v7a", "arm64-v8a"
+ }
+ }
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+
+ 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.androidxccorektx
+ implementation rootProject.ext.dependencies.androidxappcompat
+ implementation rootProject.ext.dependencies.arouter
+ implementation rootProject.ext.dependencies.rxandroid
+ compileOnly rootProject.ext.dependencies.aspectj
+ kapt rootProject.ext.dependencies.aroutercompiler
+ implementation rootProject.ext.dependencies.mogowebsocket
+ implementation rootProject.ext.dependencies.circleimageview
+ implementation rootProject.ext.dependencies.androidxconstraintlayout
+ implementation rootProject.ext.dependencies.androidxrecyclerview
+
+ if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
+ implementation rootProject.ext.dependencies.modulecommon
+ implementation rootProject.ext.dependencies.moduleservice
+ implementation rootProject.ext.dependencies.mogo_core_data
+ implementation rootProject.ext.dependencies.mogo_core_utils
+ implementation rootProject.ext.dependencies.mogo_core_function_api
+ implementation rootProject.ext.dependencies.mogo_core_function_call
+ implementation rootProject.ext.dependencies.mogo_core_res
+ } else {
+ implementation project(':modules:mogo-module-common')
+ implementation project(':modules:mogo-module-service')
+ implementation project(':core:mogo-core-data')
+ implementation project(':core:mogo-core-utils')
+ implementation project(':core:mogo-core-function-api')
+ implementation project(':core:mogo-core-function-call')
+ implementation project(':core:mogo-core-res')
+ }
+}
+
+apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
diff --git a/core/function-impl/mogo-core-function-chat/consumer-rules.pro b/core/function-impl/mogo-core-function-chat/consumer-rules.pro
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core/function-impl/mogo-core-function-chat/gradle.properties b/core/function-impl/mogo-core-function-chat/gradle.properties
new file mode 100644
index 0000000000..63866596d3
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/gradle.properties
@@ -0,0 +1,3 @@
+GROUP=com.mogo.eagle.core.function.impl
+POM_ARTIFACT_ID=v2x
+VERSION_CODE=1
diff --git a/core/function-impl/mogo-core-function-chat/libs/arm64-v8a/libgmesdk.so b/core/function-impl/mogo-core-function-chat/libs/arm64-v8a/libgmesdk.so
new file mode 100644
index 0000000000..b65f686af8
Binary files /dev/null and b/core/function-impl/mogo-core-function-chat/libs/arm64-v8a/libgmesdk.so differ
diff --git a/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmecodec.so b/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmecodec.so
new file mode 100644
index 0000000000..ef0012b4fd
Binary files /dev/null and b/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmecodec.so differ
diff --git a/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmesdk.so b/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmesdk.so
new file mode 100644
index 0000000000..9bdb9f2e54
Binary files /dev/null and b/core/function-impl/mogo-core-function-chat/libs/armeabi-v7a/libgmesdk.so differ
diff --git a/core/function-impl/mogo-core-function-chat/libs/gmesdk.jar b/core/function-impl/mogo-core-function-chat/libs/gmesdk.jar
new file mode 100644
index 0000000000..ddafacefb7
Binary files /dev/null and b/core/function-impl/mogo-core-function-chat/libs/gmesdk.jar differ
diff --git a/core/function-impl/mogo-core-function-chat/proguard-rules.pro b/core/function-impl/mogo-core-function-chat/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/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/core/function-impl/mogo-core-function-chat/src/main/AndroidManifest.xml b/core/function-impl/mogo-core-function-chat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..cd75fea39d
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/MoGoChatProvider.kt b/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/MoGoChatProvider.kt
new file mode 100644
index 0000000000..ca37017785
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/MoGoChatProvider.kt
@@ -0,0 +1,37 @@
+package com.mogo.eagle.core.function.chat
+
+import android.content.Context
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.mogo.eagle.core.function.api.chat.IMoGoChatProvider
+import com.mogo.eagle.core.function.api.chat.biz.ChatConsts
+import com.mogo.eagle.core.function.api.chat.biz.IMoGoChatFacade
+import com.mogo.eagle.core.function.chat.facade.MoGoChatFacade
+import com.mogo.eagle.core.function.chat.facade.ui.CallChatWindowManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@Route(path = ChatConsts.CHAT_PROVIDER_PATH)
+class MoGoChatProvider: IMoGoChatProvider {
+
+ private val facade by lazy {
+ MoGoChatFacade
+ }
+
+ private val chatWindowManager by lazy {
+ CallChatWindowManager()
+ }
+
+ override val functionName = "MoGoChatProvider"
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ override fun init(context: Context?) {
+ facade.init(context)
+ chatWindowManager.init()
+ }
+
+ override fun onDestroy() {
+ facade.onDestroy()
+ chatWindowManager.destroy()
+ }
+
+ override fun chat(): IMoGoChatFacade = facade
+}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/facade/MoGoChatFacade.kt b/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/facade/MoGoChatFacade.kt
new file mode 100644
index 0000000000..3a249b884c
--- /dev/null
+++ b/core/function-impl/mogo-core-function-chat/src/main/java/com/mogo/eagle/core/function/chat/facade/MoGoChatFacade.kt
@@ -0,0 +1,1140 @@
+package com.mogo.eagle.core.function.chat.facade
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.text.TextUtils
+import com.google.gson.Gson
+import com.mogo.eagle.core.function.chat.facade.gme.GMEApi
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig
+import com.mogo.eagle.core.data.chat.UserInfo
+import com.mogo.eagle.core.data.chat.socket.Message
+import com.mogo.eagle.core.data.chat.socket.TeammateInfo
+import com.mogo.eagle.core.function.api.chat.biz.*
+import com.mogo.eagle.core.function.api.chat.biz.IMCallType.CALL_TYPE_DEFAULT
+import com.mogo.eagle.core.function.api.chat.biz.IMCallType.CALL_TYPE_VEHICLE_TEAM
+import com.mogo.eagle.core.function.api.chat.biz.IMCallType.CALL_TYPE_VOICE
+import com.mogo.eagle.core.function.api.chat.biz.IMType.*
+import com.mogo.eagle.core.function.chat.facade.analytics.ChatAnalyticsFacade
+import com.mogo.eagle.core.function.chat.facade.audio.AudioFocusFacade
+import com.mogo.eagle.core.function.chat.facade.bridge.BridgeApi
+import com.mogo.eagle.core.function.chat.facade.consts.PUSH_MSG_AGREE_ENTER
+import com.mogo.eagle.core.function.chat.facade.consts.PUSH_MSG_CREATE_ROOM
+import com.mogo.eagle.core.function.chat.facade.consts.PUSH_MSG_DENY_ENTER
+import com.mogo.eagle.core.function.chat.facade.consts.PUSH_MSG_HANG_UP
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.EnterRoomFail
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.EnterRoomSuccess
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.ExitRoomSuccess
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.InitFail
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.InitSuccess
+import com.mogo.eagle.core.function.chat.facade.gme.GmeState.UserChangeInRoom
+import com.mogo.eagle.core.function.chat.facade.media.MedialControlFacade
+import com.mogo.eagle.core.function.chat.facade.net.ChatServiceModel
+import com.mogo.eagle.core.function.chat.facade.net.bean.CallRequestParam
+import com.mogo.eagle.core.function.chat.facade.net.bean.ConnectStatusParam
+import com.mogo.eagle.core.function.chat.facade.socket.SocketConnectManager
+import com.mogo.eagle.core.function.chat.facade.utils.log
+import com.mogo.eagle.core.function.chat.facade.voice.VoiceControlFacade
+import com.mogo.eagle.core.utilcode.kotlin.safeCancel
+import com.mogo.eagle.core.utilcode.util.Utils
+import kotlinx.coroutines.*
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS
+import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.selects.select
+import java.lang.ref.WeakReference
+import java.util.concurrent.TimeUnit.SECONDS
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.atomic.AtomicReference
+import kotlin.properties.Delegates
+
+object MoGoChatFacade: IMoGoChatFacade {
+
+ /**
+ * 是否初始化的标记
+ */
+ private val hasInit by lazy { AtomicBoolean(false) }
+
+ private var contextHolder: WeakReference? = null
+
+ /**
+ * SocketClient实例
+ */
+ private val client by lazy {
+ SocketConnectManager.instance()
+ }
+
+ /**
+ * 车聊相关后台接口
+ */
+ private val serverApi by lazy {
+ ChatServiceModel()
+ }
+
+ /**
+ * 负责处理长链接下行数据的管道
+ */
+ @ExperimentalCoroutinesApi
+ private var channel4SocketMsg : Channel = Channel(RENDEZVOUS)
+ @Synchronized
+ get() {
+ return if (field.isClosedForSend || field.isClosedForReceive) {
+ field = Channel(RENDEZVOUS)
+ field
+ } else {
+ field
+ }
+ }
+
+ /**
+ * 负责处理GmeSdk的各种消息类型
+ */
+ @ExperimentalCoroutinesApi
+ private var channel4GmeState: Channel = Channel(RENDEZVOUS)
+ @Synchronized
+ get() {
+ return if (field.isClosedForReceive || field.isClosedForSend) {
+ field = Channel(RENDEZVOUS)
+ field
+ } else {
+ field
+ }
+ }
+
+ private var onInComingCallback: WeakReference? = null
+
+ private var onCallingInterrupt: WeakReference? = null
+
+ private var roomId by Delegates.observable(0) { _, _, newValue ->
+ SocketConnectManager.setRoomId(newValue)
+ }
+
+ private val openId by lazy {
+ AtomicReference()
+ }
+
+ private val scopeIndex by lazy {
+ AtomicInteger(0)
+ }
+
+ private var mainScope: CoroutineScope = acquireScope()
+ @Synchronized
+ get() {
+ if (field.isActive) {
+ return field
+ }
+ val scope = acquireScope()
+ field = scope
+ return field
+ }
+
+ private fun acquireScope(): CoroutineScope {
+ return CoroutineScope(Handler(Looper.getMainLooper()).asCoroutineDispatcher("chat-service") + SupervisorJob() + CoroutineName("chat-service-${scopeIndex.getAndIncrement()}"))
+ }
+
+ private var callStatus by Delegates.observable(INIT_CALL) { _, _, newValue ->
+ log(ChatConsts.TAG, "call-status: ${newValue.toText()}")
+ }
+
+ @ExperimentalCoroutinesApi
+ private val gmeCallback: ((state: GmeState) -> Unit) = { state ->
+ mainScope.launch {
+ channel4GmeState.send(state)
+ }
+ }
+
+ private var callType by Delegates.observable(CALL_TYPE_DEFAULT) { _, oldValue, newValue ->
+ log(ChatConsts.TAG, "call type change: oldValue: $oldValue - newValue: $newValue")
+ }
+
+ private val sender by lazy { AtomicReference(null) }
+ private val receiver by lazy { AtomicReference(null) }
+ private val mySelf by lazy { AtomicReference(null) }
+
+ @ExperimentalCoroutinesApi
+ internal fun init(context: Context?) {
+ BridgeApi.init(context)
+ context?.let {
+ contextHolder = WeakReference(it)
+ }
+ if (hasInit.compareAndSet(false, true)) {
+ initSocketService()
+ voice().register()
+ }
+ }
+
+ private fun context(): Context = contextHolder?.get() ?: Utils.getApp()
+
+ @ExperimentalCoroutinesApi
+ private fun initSocketService() {
+ log(ChatConsts.TAG, "-- initSocketService --")
+ SocketConnectManager.setOnMsgReceiveCb {
+ handleMessage(it)
+ }
+ SocketConnectManager.init()
+ }
+
+ @ExperimentalCoroutinesApi
+ private fun handleMessage(msg: String) {
+ mainScope.launch {
+ log(ChatConsts.TAG, "长链下行消息: $msg")
+ val map = Gson().fromJson