Merge branch 'master' of gitlab.zhidaoauto.com:ecos/yycp-service/Launcher
# Conflicts: # gradle.properties # modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/entrance/EntranceFragment.java # modules/mogo-module-service/src/main/java/com/mogo/module/service/MogoServices.java # modules/mogo-module-service/src/main/java/com/mogo/module/service/marker/MapMarkerManager.java
12
.idea/gradle.xml
generated
@@ -12,8 +12,9 @@
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/foudations" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-base-services-apk" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-base-services-sdk" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-commons" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-connection" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-utils" />
|
||||
<option value="$PROJECT_DIR$/libraries" />
|
||||
<option value="$PROJECT_DIR$/libraries/map-amap" />
|
||||
@@ -28,17 +29,24 @@
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-authorize" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-back" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-common" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-event-panel" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-event-panel-noop" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-extensions" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-gps-simulator" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-gps-simulator-debug" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-gps-simulator-noop" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-guide" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-left-panel" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-left-panel-noop" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-main" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-map" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-media" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-obu" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-search" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-service" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-share" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-splash" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-splash-noop" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-v2x" />
|
||||
<option value="$PROJECT_DIR$/services" />
|
||||
<option value="$PROJECT_DIR$/services/mogo-service" />
|
||||
<option value="$PROJECT_DIR$/services/mogo-service-api" />
|
||||
|
||||
2
.idea/misc.xml
generated
@@ -4,7 +4,7 @@
|
||||
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
|
||||
<groovy codeStyle="LEGACY" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
</project>
|
||||
35
app/README.md
Normal file
@@ -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 功能引入
|
||||
@@ -39,11 +39,14 @@ android {
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.release
|
||||
debuggable = true
|
||||
minifyEnabled false
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
shrinkResources false
|
||||
signingConfig signingConfigs.release
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
@@ -63,9 +66,12 @@ android {
|
||||
independent {
|
||||
manifest.srcFile 'src/independent/AndroidManifest.xml'
|
||||
}
|
||||
e8xx {
|
||||
e8xx{
|
||||
manifest.srcFile 'src/e8xx/AndroidManifest.xml'
|
||||
}
|
||||
em4 {
|
||||
manifest.srcFile 'src/em4/AndroidManifest.xml'
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "product", "basic", "env"
|
||||
@@ -77,10 +83,11 @@ 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'
|
||||
buildConfigField 'String', 'SOCKET_APP_ID', '\"com.mogo.launcher\"'
|
||||
}
|
||||
// launcher app
|
||||
launcher{
|
||||
@@ -88,10 +95,11 @@ 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'
|
||||
buildConfigField 'String', 'SOCKET_APP_ID', '\"com.mogo.launcher\"'
|
||||
}
|
||||
// f系列-分体机全系列,未细分
|
||||
f8xx{
|
||||
@@ -99,13 +107,44 @@ android {
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'false'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// e系列
|
||||
// e系列,采用Launcher方案
|
||||
e8xx {
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// 同上
|
||||
em4 {
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// e系列-2+32,对标D系列2+32,采用独立app的形式
|
||||
em3 {
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// e系列-1+16,对标D系列1+16,采用独立app形式
|
||||
em1 {
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// d系列
|
||||
d8xx {
|
||||
@@ -113,6 +152,26 @@ android {
|
||||
// 使用同行者语音
|
||||
buildConfigField 'int', 'AIType','1'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// d系列 1+16 版本
|
||||
d82x{
|
||||
dimension "product"
|
||||
// 使用同行者语音
|
||||
buildConfigField 'int', 'AIType','1'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
}
|
||||
// 比亚迪
|
||||
bydauto{
|
||||
dimension "product"
|
||||
// 不使用语音
|
||||
buildConfigField 'int', 'AIType','0'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'false'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,其他车机,比亚迪定为1
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '1'
|
||||
}
|
||||
qa {
|
||||
dimension "env"
|
||||
@@ -189,18 +248,10 @@ dependencies {
|
||||
|
||||
implementation rootProject.ext.dependencies.carcallprovider
|
||||
implementation rootProject.ext.dependencies.carcall
|
||||
implementation rootProject.ext.dependencies.guideshowprovider
|
||||
implementation rootProject.ext.dependencies.guideshow
|
||||
|
||||
implementation rootProject.ext.dependencies.moduleV2x
|
||||
implementation rootProject.ext.dependencies.moduletanlu, {
|
||||
exclude group: 'com.mogo.module', module: 'module-share'
|
||||
}
|
||||
|
||||
implementation rootProject.ext.dependencies.modulepushbase
|
||||
launcherImplementation rootProject.ext.dependencies.modulepush
|
||||
independentImplementation rootProject.ext.dependencies.modulepushnoop
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
launcherImplementation rootProject.ext.dependencies.modulemainlauncher
|
||||
independentImplementation rootProject.ext.dependencies.modulemainindependent
|
||||
@@ -209,24 +260,28 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.modulesearch
|
||||
implementation rootProject.ext.dependencies.mogomoduleguide
|
||||
implementation rootProject.ext.dependencies.mogomoduleauth
|
||||
debugImplementation rootProject.ext.dependencies.gpssimulatordebug
|
||||
releaseImplementation rootProject.ext.dependencies.gpssimulatornoop
|
||||
implementation rootProject.ext.dependencies.modulemedia
|
||||
implementation rootProject.ext.dependencies.moduleservice
|
||||
implementation rootProject.ext.dependencies.modulesplash
|
||||
implementation rootProject.ext.dependencies.moduleV2x
|
||||
} else {
|
||||
launcherImplementation project(':main-extensions:mogo-module-main-launcher')
|
||||
// launcherImplementation project(':modules:mogo-module-main')
|
||||
independentImplementation project(':main-extensions:mogo-module-main-independent')
|
||||
implementation project(':foudations:mogo-commons')
|
||||
implementation project(':modules:mogo-module-common')
|
||||
implementation project(':modules:mogo-module-search')
|
||||
implementation project(':modules:mogo-module-guide')
|
||||
implementation project(':modules:mogo-module-authorize')
|
||||
debugImplementation project(':modules:mogo-module-gps-simulator-debug')
|
||||
releaseImplementation project(':modules:mogo-module-gps-simulator-noop')
|
||||
implementation project(':modules:mogo-module-media')
|
||||
implementation project(':modules:mogo-module-service')
|
||||
implementation project(':modules:mogo-module-splash')
|
||||
implementation project(':modules:mogo-module-v2x')
|
||||
}
|
||||
|
||||
apply from: "./functions/baseservices.gradle"
|
||||
apply from: "./functions/socketpush.gradle"
|
||||
apply from: "./functions/gpssimulator.gradle"
|
||||
apply from: "./functions/eventpanel.gradle"
|
||||
apply from: "./functions/leftpanel.gradle"
|
||||
}
|
||||
|
||||
//android.applicationVariants.all { variant ->
|
||||
@@ -289,6 +344,7 @@ def getGitCommit() {
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
|
||||
it.getTasks().iterator().forEachRemaining {
|
||||
def nameLowCase = it.name
|
||||
|
||||
@@ -311,5 +367,3 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//apply plugin: 'arouterhook'
|
||||
1
app/functions/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# 不同渠道,依赖的实现不一样,需要各个渠道都去依赖各自需要的实现,渠道太多导致build.gradle 文件臃肿,可以通过分gradle文件方式减少臃肿
|
||||
26
app/functions/baseservices.gradle
Normal file
@@ -0,0 +1,26 @@
|
||||
// 基础服务:仅比亚迪渠道用sdk方式实现,其他都基于apk基础服务
|
||||
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
bydautoImplementation 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 {
|
||||
bydautoImplementation 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')
|
||||
}
|
||||
}
|
||||
25
app/functions/eventpanel.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
// 道路事件操作面板
|
||||
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
d82xImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
em1Implementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
bydautoImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
|
||||
d8xxImplementation rootProject.ext.dependencies.moduleventpanel
|
||||
em4Implementation rootProject.ext.dependencies.moduleventpanel
|
||||
e8xxImplementation rootProject.ext.dependencies.moduleventpanel
|
||||
f8xxImplementation rootProject.ext.dependencies.moduleventpanel
|
||||
em3Implementation rootProject.ext.dependencies.moduleventpanel
|
||||
} else {
|
||||
d82xImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
em1Implementation project(':modules:mogo-module-event-panel-noop')
|
||||
bydautoImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
|
||||
d8xxImplementation project(':modules:mogo-module-event-panel')
|
||||
em4Implementation project(':modules:mogo-module-event-panel')
|
||||
e8xxImplementation project(':modules:mogo-module-event-panel')
|
||||
f8xxImplementation project(':modules:mogo-module-event-panel')
|
||||
em3Implementation project(':modules:mogo-module-event-panel')
|
||||
}
|
||||
}
|
||||
11
app/functions/gpssimulator.gradle
Normal file
@@ -0,0 +1,11 @@
|
||||
// 基于后台轨迹模拟的gps模拟服务
|
||||
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
debugImplementation rootProject.ext.dependencies.gpssimulatordebug
|
||||
releaseImplementation rootProject.ext.dependencies.gpssimulatornoop
|
||||
} else {
|
||||
debugImplementation project(':modules:mogo-module-gps-simulator-debug')
|
||||
releaseImplementation project(':modules:mogo-module-gps-simulator-noop')
|
||||
}
|
||||
}
|
||||
26
app/functions/leftpanel.gradle
Normal file
@@ -0,0 +1,26 @@
|
||||
// 辅助驾驶占位模块,目前部分车机不上辅助驾驶功能,使用该模块能力代替
|
||||
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
d82xImplementation rootProject.ext.dependencies.moduleleftpanel
|
||||
em1Implementation rootProject.ext.dependencies.moduleleftpanel
|
||||
bydautoImplementation rootProject.ext.dependencies.moduleleftpanel
|
||||
|
||||
d8xxImplementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
em4Implementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
e8xxImplementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
e8xxImplementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
f8xxImplementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
em3Implementation rootProject.ext.dependencies.moduleleftpanelnoop
|
||||
} else {
|
||||
d82xImplementation project(':modules:mogo-module-left-panel')
|
||||
em1Implementation project(':modules:mogo-module-left-panel')
|
||||
bydautoImplementation project(':modules:mogo-module-left-panel')
|
||||
|
||||
d8xxImplementation project(':modules:mogo-module-left-panel-noop')
|
||||
em4Implementation project(':modules:mogo-module-left-panel-noop')
|
||||
e8xxImplementation project(':modules:mogo-module-left-panel-noop')
|
||||
f8xxImplementation project(':modules:mogo-module-left-panel-noop')
|
||||
em3Implementation project(':modules:mogo-module-left-panel-noop')
|
||||
}
|
||||
}
|
||||
7
app/functions/socketpush.gradle
Normal file
@@ -0,0 +1,7 @@
|
||||
// 基于socket长链的push推送
|
||||
|
||||
project.dependencies {
|
||||
implementation rootProject.ext.dependencies.modulepushbase
|
||||
launcherImplementation rootProject.ext.dependencies.modulepush
|
||||
independentImplementation rootProject.ext.dependencies.modulepushnoop
|
||||
}
|
||||
352
app/proguard-rules.pro
vendored
@@ -19,3 +19,355 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
|
||||
#
|
||||
#-------------------------------------------基本不用动区域----------------------------------------------
|
||||
#
|
||||
#
|
||||
# -----------------------------基本 -----------------------------
|
||||
|
||||
# 指定代码的压缩级别 0 - 7(指定代码进行迭代优化的次数,在Android里面默认是5,这条指令也只有在可以优化时起作用。)
|
||||
-optimizationpasses 5
|
||||
# 混淆时不会产生形形色色的类名(混淆时不使用大小写混合类名)
|
||||
-dontusemixedcaseclassnames
|
||||
# 指定不去忽略非公共的库类(不跳过library中的非public的类)
|
||||
-dontskipnonpubliclibraryclasses
|
||||
# 指定不去忽略包可见的库类的成员
|
||||
-dontskipnonpubliclibraryclassmembers
|
||||
#不进行优化,建议使用此选项,
|
||||
-dontoptimize
|
||||
# 不进行预校验,Android不需要,可加快混淆速度。
|
||||
-dontpreverify
|
||||
|
||||
# 屏蔽警告,暂不开启。用于抛出异常
|
||||
#-ignorewarnings
|
||||
# 指定混淆是采用的算法,后面的参数是一个过滤器
|
||||
# 这个过滤器是谷歌推荐的算法,一般不做更改
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
# 保护代码中的Annotation不被混淆
|
||||
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod
|
||||
# 避免混淆泛型, 这在JSON实体映射时非常重要
|
||||
-keepattributes Signature
|
||||
# 抛出异常时保留代码行号
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
#优化时允许访问并修改有修饰符的类和类的成员,这可以提高优化步骤的结果。
|
||||
# 比如,当内联一个公共的getter方法时,这也可能需要外地公共访问。
|
||||
# 虽然java二进制规范不需要这个,要不然有的虚拟机处理这些代码会有问题。当有优化和使用-repackageclasses时才适用。
|
||||
#指示语:不能用这个指令处理库中的代码,因为有的类和类成员没有设计成public ,而在api中可能变成public
|
||||
-allowaccessmodification
|
||||
# 混淆时记录日志(打印混淆的详细信息)
|
||||
# 这句话能够使我们的项目混淆后产生映射文件
|
||||
# 包含有类名->混淆后类名的映射关系
|
||||
-verbose
|
||||
|
||||
|
||||
#
|
||||
# ----------------------------- 默认保留 -----------------------------
|
||||
#
|
||||
#----------------------------------------------------
|
||||
# 保持哪些类不被混淆
|
||||
#继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Fragment
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class * extends android.view.View
|
||||
|
||||
-keep public class androidx.*{*;}
|
||||
-keep public class * extends androidx.*{*;}
|
||||
-keep interface androidx.* {*;}
|
||||
-dontwarn androidx.**
|
||||
|
||||
-dontwarn android.support.design.**
|
||||
-keep public class android.support.design.R$* { *; }
|
||||
-keep class com.google.android.material.* {*;}
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
#这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆
|
||||
#表示不混淆Activity中参数是View的方法
|
||||
-keepclassmembers class * extends android.app.Activity{
|
||||
public void *(android.view.View);
|
||||
}
|
||||
#表示不混淆枚举中的values()和valueOf()方法
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
#表示不混淆任何一个View中的setXxx()和getXxx()方法,
|
||||
#因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。
|
||||
-keep public class * extends android.view.View{
|
||||
*** get*();
|
||||
void set*(***);
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
#表示不混淆Parcelable
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable *;
|
||||
}
|
||||
|
||||
# 这指定了继承Serizalizable的类的如下成员不被移除混淆
|
||||
-keepclassmembers class * implements java.io.Serializable {
|
||||
static final long serialVersionUID;
|
||||
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||
private void writeObject(java.io.ObjectOutputStream);
|
||||
private void readObject(java.io.ObjectInputStream);
|
||||
java.lang.Object writeReplace();
|
||||
java.lang.Object readResolve();
|
||||
}
|
||||
|
||||
# 保留R下面的资源
|
||||
-keep class **.R$* {
|
||||
*;
|
||||
}
|
||||
|
||||
#不混淆资源类下static的
|
||||
-keepclassmembers class **.R$* {
|
||||
public static <fields>;
|
||||
}
|
||||
|
||||
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
|
||||
-keepclassmembers class * {
|
||||
void *(**On*Event);
|
||||
void *(**On*Listener);
|
||||
}
|
||||
|
||||
#(可选)避免Log打印输出
|
||||
-assumenosideeffects class android.util.Log {
|
||||
public static *** v(...);
|
||||
public static *** d(...);
|
||||
public static *** i(...);
|
||||
public static *** w(...);
|
||||
}
|
||||
|
||||
#kotlin
|
||||
-keep class kotlin.* { *; }
|
||||
-keepclassmembernames class kotlinx.*{
|
||||
volatile <fields>;
|
||||
}
|
||||
-keep class kotlin.Metadata { *; }
|
||||
-dontwarn kotlin.*
|
||||
-dontwarn kotlin.**
|
||||
-keepclassmembers class **$WhenMappings {
|
||||
<fields>;
|
||||
}
|
||||
-keepclassmembers class kotlin.Metadata {
|
||||
public <methods>;
|
||||
}
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
|
||||
}
|
||||
-keepclassmembers class kotlin.Metadata { *; }
|
||||
-keep @kotlin.Metadata class *
|
||||
-keepclasseswithmembers @kotlin.Metadata class * { *; }
|
||||
|
||||
-dontwarn android.telephony.TelephonyManager.**
|
||||
-keep class android.telephony.TelephonyManager.**{*;}
|
||||
|
||||
#----------------------------------------第三方库----------------------------------------------
|
||||
#-----高德地图-----
|
||||
|
||||
#内置语音 V5.6.0之后
|
||||
-keep class com.alibaba.idst.nls.**{*;}
|
||||
-keep class com.google.**{*;}
|
||||
-keep class com.nlspeech.nlscodec.** {*;}
|
||||
-keep public class com.alibaba.mit.alitts.*{*;}
|
||||
-keep class com.alibaba.mit.alitts.** {*;}
|
||||
-dontwarn com.alibaba.mit.alitts.ICallback
|
||||
|
||||
#3D 地图 V5.0.0之后:
|
||||
-keep class com.amap.api.maps.**{*;}
|
||||
-keep class com.autonavi.**{*;}
|
||||
-keep class com.amap.api.trace.**{*;}
|
||||
#定位
|
||||
-keep class com.loc.** {*;}
|
||||
-keep class com.amap.api.location.**{*;}
|
||||
-keep class com.amap.api.fence.**{*;}
|
||||
-keep class com.autonavi.aps.amapapi.model.**{*;}
|
||||
#搜索
|
||||
-keep class com.amap.api.services.**{*;}
|
||||
#导航
|
||||
-keep class com.amap.api.navi.**{*;}
|
||||
|
||||
|
||||
#-----Gson-----
|
||||
-dontwarn sun.misc.**
|
||||
# Application classes that will be serialized/deserialized over Gson
|
||||
-keep class com.google.gson.examples.android.model.** { <fields>; }
|
||||
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * extends com.google.gson.TypeAdapter
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
# Prevent R8 from leaving Data object members always null
|
||||
-keepclassmembers,allowobfuscation class * {
|
||||
@com.google.gson.annotations.SerializedName <fields>;
|
||||
}
|
||||
|
||||
#-----ARouter-----
|
||||
-keep public class com.alibaba.android.arouter.routes.**{*;}
|
||||
-keep public class com.alibaba.android.arouter.facade.**{*;}
|
||||
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
|
||||
# If you use the byType method to obtain Service, add the following rules to protect the interface:
|
||||
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
|
||||
# If single-type injection is used, that is, no interface is defined to implement IProvider, the following rules need to be added to protect the implementation
|
||||
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
|
||||
|
||||
#-----Glide-----
|
||||
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||
-keep public class * extends com.bumptech.glide.module.AppGlideModule {
|
||||
<init>(...);
|
||||
}
|
||||
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
|
||||
*** rewind();
|
||||
}
|
||||
|
||||
#如果你的 target API 低于 Android API 27,请添加:
|
||||
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
|
||||
|
||||
#-----Fresco-----
|
||||
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
|
||||
-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize
|
||||
-keep @com.facebook.common.internal.DoNotStrip class *
|
||||
-keepclassmembers class * {
|
||||
@com.facebook.common.internal.DoNotStrip *;
|
||||
}
|
||||
-keep @com.facebook.soloader.DoNotOptimize class *
|
||||
-keepclassmembers class * {
|
||||
@com.facebook.soloader.DoNotOptimize *;
|
||||
}
|
||||
-keepclassmembers class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keep public class com.facebook.soloader.SoLoader {
|
||||
public static void init(android.content.Context, int);
|
||||
}
|
||||
|
||||
-dontwarn okio.**
|
||||
-dontwarn com.squareup.okhttp.**
|
||||
-dontwarn okhttp3.**
|
||||
-dontwarn javax.annotation.**
|
||||
-dontwarn com.android.volley.toolbox.**
|
||||
-dontwarn com.facebook.infer.**
|
||||
|
||||
#-----Okio-----
|
||||
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
-dontwarn com.squareup.**
|
||||
-dontwarn okio.**
|
||||
|
||||
#-----OkHttp-----
|
||||
# JSR 305 annotations are for embedding nullability information.
|
||||
-dontwarn javax.annotation.**
|
||||
# A resource is loaded with a relative path so the package of this class must be preserved.
|
||||
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
|
||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||
|
||||
#-----Retrofit-----
|
||||
# Retrofit does reflection on method and parameter annotations.
|
||||
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
|
||||
# Retain service method parameters when optimizing.
|
||||
-keepclassmembers,allowshrinking,allowobfuscation interface * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
# Ignore annotation used for build tooling.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
# Ignore JSR 305 annotations for embedding nullability information.
|
||||
-dontwarn javax.annotation.**
|
||||
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
|
||||
-dontwarn kotlin.Unit
|
||||
# Top-level functions that can only be used by Kotlin.
|
||||
-dontwarn retrofit2.KotlinExtensions
|
||||
-dontwarn retrofit2.KotlinExtensions$*
|
||||
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
|
||||
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
|
||||
-if interface * { @retrofit2.http.* <methods>; }
|
||||
-keep,allowobfuscation interface <1>
|
||||
|
||||
#-----ProtoBuf-----
|
||||
-keep class com.google.protobuf.** {*;}
|
||||
|
||||
#-----GSYVideoPlayer-----
|
||||
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.**
|
||||
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.utils.**
|
||||
-keep class tv.danmaku.ijk.** { *; }
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
|
||||
#-----EventBus-----
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class * {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
# And if you use AsyncExecutor:
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
#-----Netty-----
|
||||
-keepattributes Signature,InnerClasses
|
||||
-keep class io.netty.** {*;}
|
||||
-keep class org.apache.** {*;}
|
||||
-keep class org.apache.logging.**{*;}
|
||||
-keepclasseswithmembers class io.netty.** {*;}
|
||||
-keepclasseswithmembers class org.apache.logging.**{*;}
|
||||
-keep class org.apache.http.**{*;}
|
||||
-dontwarn io.netty.**
|
||||
-dontwarn sun.**
|
||||
|
||||
#-----ZhiDaoService-----
|
||||
-keep class com.zhidao.auto.platform.**{*;}
|
||||
-keep class com.zhidao.auto.carcorder.**{*;}
|
||||
-keep class com.zhidaohulian.**{*;}
|
||||
-keep class com.zhidao.boot.**{*;}
|
||||
-keep class com.elegant.**{*;}
|
||||
-keep class com.zhidao.socketsdk.**{*;}
|
||||
-keep class com.zhidao.socket.**{*;}
|
||||
-keep class com.zhidao.ptech.**{*;}
|
||||
-keep class com.zhidao.autopilotcore.**{*;}
|
||||
-keep class com.zhidao.autopilot.support.**{*;}
|
||||
-keep class com.zhidao.voice.library.**{*;}
|
||||
-keep class com.zhidao.voicesdk.**{*;}
|
||||
-keep class com.zhidao.smartv2x.**{*;}
|
||||
-keep class com.zhidao.accountsdk.**{*;}
|
||||
-keep class com.zhidao.account.**{*;}
|
||||
-keep class com.zhidao.locupload.**{*;}
|
||||
-keep class com.zhidao.tcloginsdk.**{*;}
|
||||
-keep class com.zhidao.utils.**{*;}
|
||||
-keep class com.hw.videoprocessor.**{*;}
|
||||
-dontwarn com.elegant.network.**
|
||||
|
||||
-keep class com.bytedance.boost_multidex.**{*;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6
app/src/em4/AndroidManifest.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:sharedUserId="android.uid.system"
|
||||
package="com.mogo.launcher">
|
||||
</manifest>
|
||||
@@ -2,6 +2,7 @@ package com.mogo.launcher;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
@@ -9,6 +10,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.commons.network.Utils;
|
||||
import com.mogo.commons.storage.SpStorage;
|
||||
import com.mogo.module.authorize.authprovider.invoke.AuthorizeConstant;
|
||||
import com.mogo.module.carchatting.card.CallChatConstant;
|
||||
import com.mogo.module.common.MogoModule;
|
||||
@@ -19,11 +22,15 @@ 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.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;
|
||||
import com.zhidao.mogo.module.event.panel.EventPanelConstants;
|
||||
import com.zhidao.mogo.module.left.panel.LeftPanelConst;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
@@ -41,59 +48,111 @@ 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(AuthorizeConstant.PATH_AGREEMENT_FRAGMENT, AuthorizeConstant.PATH_AGREEMENT_MODULE_NAME));
|
||||
// MogoModulePaths.addModule(new MogoModule(PATH_GUIDE_FRAGMENT, PATH_GUIDE_MODULE_NAME));
|
||||
MogoModulePaths.addModule( new MogoModule( MogoServicePaths.PATH_AGREEMENT, 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.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));
|
||||
|
||||
if (!DebugConfig.isLauncher()) {
|
||||
PersistentManager.getInstance().initManager(this);
|
||||
Intent intent = new Intent(this, MogoMainService.class);
|
||||
startService(intent);
|
||||
if(DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_BYD){
|
||||
MogoModulePaths.addModule( new MogoModule( CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME ) );
|
||||
}
|
||||
Log.i("timer", "cost " + (System.currentTimeMillis() - start) + "ms");
|
||||
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.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 ) );
|
||||
|
||||
if ( !DebugConfig.isLauncher() ) {
|
||||
PersistentManager.getInstance().initManager( this );
|
||||
Intent intent = new Intent( this, MogoMainService.class );
|
||||
startService( intent );
|
||||
}
|
||||
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.setProductFlavor( BuildConfig.FLAVOR_product );
|
||||
DebugConfig.setSocketAppId( BuildConfig.SOCKET_APP_ID );
|
||||
}
|
||||
|
||||
@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.");
|
||||
}
|
||||
prepareBaseService(2_000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础服务:passport、location、socket
|
||||
*/
|
||||
private void prepareBaseService(long delay) {
|
||||
UiThreadHandler.postDelayed( () -> {
|
||||
final IMogoServiceApis apis = ARouter.getInstance().navigation( IMogoServiceApis.class );
|
||||
// 第三方平台的sn是服务端生成的,所以必须在返回后才能开启
|
||||
if ( TextUtils.isEmpty( Utils.getSn() ) ) {
|
||||
preparePassportEnvironment( apis, () -> {
|
||||
prepareSocketAndLocationServices( apis );
|
||||
} );
|
||||
} else {
|
||||
preparePassportEnvironment( apis, null );
|
||||
prepareSocketAndLocationServices( apis );
|
||||
}
|
||||
}, delay );
|
||||
}
|
||||
|
||||
private void preparePassportEnvironment( IMogoServiceApis apis, Runnable after ) {
|
||||
apis.getPassportManagerApi().requestTicket( new IMogoTicketCallback() {
|
||||
@Override
|
||||
public void onTicketGot( 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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginSuccess( String token, String sn ) {
|
||||
if ( after != null ) {
|
||||
after.run();
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void prepareSocketAndLocationServices( IMogoServiceApis apis ) {
|
||||
apis.getSocketManagerApi( getApplicationContext() ).init( getApplicationContext(), DebugConfig.getSocketAppId() );
|
||||
apis.getLocationInfoApi().start();
|
||||
apis.getMapServiceApi().getSingletonLocationClient( getApplicationContext() ).addLocationListener( location -> {
|
||||
apis.getLocationInfoApi().provideLocation( location );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
BoostMultiDex.install(base);
|
||||
protected void attachBaseContext( Context base ) {
|
||||
super.attachBaseContext( base );
|
||||
BoostMultiDex.install( base );
|
||||
}
|
||||
}
|
||||
|
||||
3
app/src/main/res/values-xhdpi-1920x1000/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_shell_name">蘑菇知途</string>
|
||||
</resources>
|
||||
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_shell_name">智慧驾驶</string>
|
||||
<string name="app_shell_name">蘑菇出行</string>
|
||||
</resources>
|
||||
|
||||
@@ -22,7 +22,6 @@ buildscript {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.alibaba:arouter-register:1.0.2"
|
||||
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
|
||||
// classpath "com.mogo.module.pluginhook:module-pluginhook:${HOOKPLUGIN_VERSION}"
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -104,8 +101,8 @@ ext {
|
||||
moduleextensions : "com.mogo.module:module-extensions:${MOGO_MODULE_EXTENSIONS_VERSION}",
|
||||
carcall : "com.mogo.module.carchatting:module-carchatting:${CARCHATTING_VERSION}",
|
||||
carcallprovider : "com.mogo.module.carchatting:module-carchatting-provider:${CARCHATTINGPROVIDER_VERSION}",
|
||||
guideshow : "com.mogo.module.guideshow:module-guideshow:${MOGO_MODULE_GUIDESHOW_VERSION}",
|
||||
guideshowprovider : "com.mogo.module.guideshow:module-guideshow-provider:${MOGO_MODULE_GUIDESHOW_PROVIDER_VERSION}",
|
||||
// guideshow : "com.mogo.module.guideshow:module-guideshow:${MOGO_MODULE_GUIDESHOW_VERSION}",
|
||||
// guideshowprovider : "com.mogo.module.guideshow:module-guideshow-provider:${MOGO_MODULE_GUIDESHOW_PROVIDER_VERSION}",
|
||||
// 在线车辆
|
||||
moduleonlinecar : "com.mogo.module:module-onlinecar:${MOGO_MODULE_ONLINECAR_VERSION}",
|
||||
// V2X
|
||||
@@ -126,6 +123,8 @@ ext {
|
||||
socketsdk : 'com.zhidao.socketsdk:socketsdk:2.1.4',
|
||||
socketsdkconnsvrprotoco : 'com.zhidao.ptech:connsvr-protoco:0.1.23',
|
||||
socketsdkprotobufjava : 'com.google.protobuf:protobuf-java:3.5.1',
|
||||
// OBU
|
||||
moduleobu : "com.mogo.module:module-obu:${MOGO_MODULE_OBU_VERSION}",
|
||||
|
||||
//
|
||||
jetbrainsannotationsjava5: "org.jetbrains:annotations-java5:15.0",
|
||||
@@ -157,5 +156,21 @@ ext {
|
||||
// 个人中心的SDK
|
||||
personalsdk : "com.zhidaoauto.person.info:data:1.0.1",
|
||||
tanluupload : "com.mogo.module:module-tanlu-upload:${TANLULIB_VERSION}",
|
||||
|
||||
// obu sdk
|
||||
obusdk : "com.zhidao.enterprise.smartv2x:smartv2x:1.0.0.1",
|
||||
//事件面板
|
||||
moduleventpanel : "com.mogo.module:module-event-panel:${MOGO_MODULE_EVENT_PANEL_VERSION}",
|
||||
// 事件面板空实现
|
||||
moduleventpanelnoop : "com.mogo.module:module-event-panel-noop:${MOGO_MODULE_EVENT_PANEL_VERSION}",
|
||||
// 左侧面板
|
||||
moduleleftpanel : "com.mogo.module:module-left-panel:${MOGO_MODULE_LEFT_PANEL_VERSION}",
|
||||
// 左侧面板空实现
|
||||
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-sdk:${MOGO_BASE_SERVICES_SDK_VERSION}",
|
||||
mogobaseserviceapk : "com.mogo.base:services-apk:${MOGO_BASE_SERVICES_APK_VERSION}",
|
||||
]
|
||||
}
|
||||
1
foudations/mogo-base-services-apk/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
7
foudations/mogo-base-services-apk/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 基实现功能
|
||||
|
||||
基础服务apk实现对应功能:位置上报、长连接、passport
|
||||
|
||||
位置上报:com.zhidao.locationinfo
|
||||
长链:com.zhidao.socketservice
|
||||
passport:
|
||||
@@ -1,5 +1,4 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
@@ -10,14 +9,9 @@ android {
|
||||
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()]
|
||||
}
|
||||
}
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -26,24 +20,32 @@ android {
|
||||
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 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.arouter
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
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()
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
3
foudations/mogo-base-services-apk/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.base
|
||||
POM_ARTIFACT_ID=services-apk
|
||||
VERSION_CODE=1
|
||||
@@ -18,4 +18,4 @@
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.base.services.apk">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
@@ -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" );
|
||||
}
|
||||
}
|
||||
@@ -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.onTicketGot( 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" );
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.mogo.connection.socket;
|
||||
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.map.listener.IMogoMapListener;
|
||||
import com.mogo.service.connection.IMessageResponse;
|
||||
import com.mogo.service.connection.IMogoMsgAckListener;
|
||||
import com.mogo.service.connection.IMogoOnMessageListener;
|
||||
import com.mogo.service.connection.IMogoSocketManager;
|
||||
@@ -31,10 +31,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* <p>
|
||||
* 长链实现:基于 netty
|
||||
*/
|
||||
|
||||
@Keep
|
||||
public class SocketManager implements IMogoSocketManager, OnSocketReceiveCallback, OnSocketAckCallback {
|
||||
|
||||
private static final String TAG = "SocketManager";
|
||||
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;
|
||||
@@ -47,6 +47,7 @@ public class SocketManager implements IMogoSocketManager, OnSocketReceiveCallbac
|
||||
mSocketConnManager.addSocketAckCallback( this );
|
||||
}
|
||||
|
||||
@Keep
|
||||
public static SocketManager getInstance( Context context ) {
|
||||
if ( sInstance == null ) {
|
||||
synchronized ( SocketManager.class ) {
|
||||
1
foudations/mogo-base-services-sdk/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
3
foudations/mogo-base-services-sdk/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## sdk实现功能
|
||||
|
||||
脱离基础服务apk实现对应功能:位置上报、长连接、passport
|
||||
53
foudations/mogo-base-services-sdk/build.gradle
Normal file
@@ -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.1.3'
|
||||
// 长链
|
||||
implementation 'com.zhidao.socket:built-in-socket:1.0.15'
|
||||
// passport
|
||||
implementation 'com.zhidao.tcloginsdk:tclogin:1.1.0'
|
||||
|
||||
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()
|
||||
2
foudations/mogo-base-services-sdk/consumer-rules.pro
Normal file
@@ -0,0 +1,2 @@
|
||||
#-----MogoBaseServiceSdk-----
|
||||
-keep class com.mogo.base.services.locationinfo.MogoLocationSource.*{*;}
|
||||
3
foudations/mogo-base-services-sdk/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.base
|
||||
POM_ARTIFACT_ID=services-sdk
|
||||
VERSION_CODE=1
|
||||
24
foudations/mogo-base-services-sdk/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# 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
|
||||
|
||||
#-----MogoBaseServiceSdk-----
|
||||
-keep class com.mogo.base.services.locationinfo.MogoLocationSource.*{*;}
|
||||
@@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@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() );
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.connection" />
|
||||
package="com.mogo.base.services">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.base.services;
|
||||
|
||||
public
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2020/7/23
|
||||
*
|
||||
* 描述
|
||||
*/
|
||||
interface BaseServicesConstants {
|
||||
|
||||
/**
|
||||
* 建立长链的通道ID
|
||||
*/
|
||||
String SOCKET_CHANNEL_ID = "dataCrawler";
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.mogo.base.services.locationinfo;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
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;
|
||||
|
||||
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( DebugConfig.getSocketAppId() ).
|
||||
setContext( context.getApplicationContext() ).
|
||||
setLoggable( DebugConfig.isDebug() ).
|
||||
setLocInterval( 2000L );
|
||||
Logger.d( TAG, "sdk - init" );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
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.tcloginsdk.LoginManager;
|
||||
import com.zhidao.tcloginsdk.model.TokenData;
|
||||
import com.zhidao.tcloginsdk.network.LoginCallback;
|
||||
|
||||
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 ) {
|
||||
LoginManager.getInstance( mContext ).login( DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_SELF_INNOVATE, DebugConfig.getProductFlavor(), new LoginCallback() {
|
||||
@Override
|
||||
public void onSuccess( TokenData.TokenResult result ) {
|
||||
if ( callback != null ) {
|
||||
callback.onLoginSuccess( result.token, result.sn );
|
||||
}
|
||||
getTicket( new TicketInfoCallback() {
|
||||
@Override
|
||||
public void onSuccess( String ticket ) {
|
||||
Logger.d( TAG, "success" );
|
||||
SpStorage.setTicket( ticket );
|
||||
if ( callback != null ) {
|
||||
callback.onTicketGot( ticket );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure( int code ) {
|
||||
Logger.d( TAG, "fail" );
|
||||
if ( callback != null ) {
|
||||
callback.onError( code, "getTicket error." );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure( int code, String msg ) {
|
||||
if ( callback != null ) {
|
||||
callback.onError( code, "login: " + msg );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
LoginManager.getInstance( context ).setNetEnviron( mode );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
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.base.services.BaseServicesConstants;
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.commons.network.Utils;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理消息分发
|
||||
* <p>
|
||||
* key - msgType
|
||||
*/
|
||||
private Map< Integer, List< IMogoOnMessageListener > > mListeners = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 管理消息回执
|
||||
* <p>
|
||||
* 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 ) )
|
||||
.setChannelId( BaseServicesConstants.SOCKET_CHANNEL_ID )
|
||||
.setOpenAnalytics( true )
|
||||
.setSn( Utils.getSn() )
|
||||
.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 ) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals( 4, 2 + 2 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#-----Foundation-Commons-----
|
||||
-keep class com.mogo.commons.data.BaseData.*{*;}
|
||||
-keep class com.mogo.commons.voice.VoiceIntentTrack
|
||||
-keep class com.mogo.commons.voice.VoiceTrack
|
||||
-keep class com.mogo.commons.voice.VoicePreemptType
|
||||
-keep interface * implements com.mogo.commons.mvp.IView
|
||||
7
foudations/mogo-commons/proguard-rules.pro
vendored
@@ -19,3 +19,10 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----Foundation-Commons-----
|
||||
-keep class com.mogo.commons.data.BaseData.*{*;}
|
||||
-keep class com.mogo.commons.voice.VoiceIntentTrack
|
||||
-keep class com.mogo.commons.voice.VoiceTrack
|
||||
-keep class com.mogo.commons.voice.VoicePreemptType
|
||||
-keep interface * implements com.mogo.commons.mvp.IView
|
||||
@@ -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,36 +102,12 @@ 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 initNetConfig() {
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.mogo.utils.logger.Logger;
|
||||
* @since 2019-12-23
|
||||
* <p>
|
||||
* 各个模块递调试信息控制接口
|
||||
* <p>
|
||||
* 注:该类已经不再是简单的调试配置,已经涉及到功能逻辑了 囧
|
||||
*/
|
||||
public class DebugConfig {
|
||||
|
||||
@@ -53,6 +55,11 @@ public class DebugConfig {
|
||||
|
||||
private static int sNetMode = NET_MODE_RELEASE;
|
||||
|
||||
/**
|
||||
* 不使用语音助手
|
||||
*/
|
||||
public static final int AI_TYPE_NOOP = 0;
|
||||
|
||||
/**
|
||||
* 语音使用同行者
|
||||
*/
|
||||
@@ -64,6 +71,18 @@ public class DebugConfig {
|
||||
|
||||
private static int sAIType = AI_TYPE_TXZ;
|
||||
|
||||
/**
|
||||
* 自研车机
|
||||
*/
|
||||
public static final int CAR_MACHINE_TYPE_SELF_INNOVATE = 0;
|
||||
|
||||
/**
|
||||
* 比亚迪的车机
|
||||
*/
|
||||
public static final int CAR_MACHINE_TYPE_BYD = 1;
|
||||
|
||||
private static int sCarMachineType = CAR_MACHINE_TYPE_SELF_INNOVATE;
|
||||
|
||||
/**
|
||||
* 获取网络环境类型
|
||||
*
|
||||
@@ -115,20 +134,39 @@ public class DebugConfig {
|
||||
|
||||
/**
|
||||
* 设置使用哪个语音助手
|
||||
* @param aiType {@link #AI_TYPE_TXZ} {@link #AI_TYPE_SPEECH}
|
||||
*
|
||||
* @param aiType {@link #AI_TYPE_NOOP} {@link #AI_TYPE_TXZ} {@link #AI_TYPE_SPEECH}
|
||||
*/
|
||||
public static void setAIType(int aiType){
|
||||
Logger.d("DebugConfig", "setAiType: " + aiType);
|
||||
public static void setAIType( int aiType ) {
|
||||
Logger.d( "DebugConfig", "setAiType: " + aiType );
|
||||
sAIType = aiType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用哪个语音助手 {@link #AI_TYPE_TXZ} {@link #AI_TYPE_SPEECH}
|
||||
* 使用哪个语音助手 {@link #AI_TYPE_NOOP} {@link #AI_TYPE_TXZ} {@link #AI_TYPE_SPEECH}
|
||||
*/
|
||||
public static int getAIType(){
|
||||
public static int getAIType() {
|
||||
return sAIType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前车机类型
|
||||
*
|
||||
* @param type {@link #CAR_MACHINE_TYPE_SELF_INNOVATE} {@link #CAR_MACHINE_TYPE_BYD}
|
||||
*/
|
||||
public static void setCarMachineType( int type ) {
|
||||
sCarMachineType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前车机类型
|
||||
*
|
||||
* @return {@link #CAR_MACHINE_TYPE_SELF_INNOVATE} {@link #CAR_MACHINE_TYPE_BYD}
|
||||
*/
|
||||
public static int getCarMachineType() {
|
||||
return sCarMachineType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否作为launcher运行
|
||||
*/
|
||||
@@ -164,4 +202,39 @@ public class DebugConfig {
|
||||
public static void setActiveAIAssistFlag( boolean sActiveAIAssistFlag ) {
|
||||
DebugConfig.sActiveAIAssistFlag = sActiveAIAssistFlag;
|
||||
}
|
||||
|
||||
private static boolean useMockObuData;
|
||||
|
||||
public static void setUseMockObuData( boolean use ) {
|
||||
useMockObuData = use;
|
||||
}
|
||||
|
||||
public static boolean isUseMockObuData() {
|
||||
return useMockObuData;
|
||||
}
|
||||
|
||||
private static String sProductFlavor;
|
||||
|
||||
public static String getProductFlavor() {
|
||||
return sProductFlavor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 产品线
|
||||
*
|
||||
* @param sProductFlavor
|
||||
*/
|
||||
public static void setProductFlavor( String sProductFlavor ) {
|
||||
DebugConfig.sProductFlavor = sProductFlavor;
|
||||
}
|
||||
|
||||
private static String sSocketAppId;
|
||||
|
||||
public static void setSocketAppId( String sSocketAppId ) {
|
||||
DebugConfig.sSocketAppId = sSocketAppId;
|
||||
}
|
||||
|
||||
public static String getSocketAppId() {
|
||||
return sSocketAppId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,14 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.utils.SoftKeyBoardJobber;
|
||||
|
||||
/**
|
||||
@@ -23,6 +28,10 @@ public abstract class MvpActivity< V extends IView, P extends Presenter< V > >
|
||||
@Override
|
||||
protected void onCreate( @Nullable Bundle savedInstanceState ) {
|
||||
super.onCreate( savedInstanceState );
|
||||
if (DebugConfig.getCarMachineType() == DebugConfig.CAR_MACHINE_TYPE_BYD) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
setContentView( getLayoutId() );
|
||||
initViews();
|
||||
mPresenter = createPresenter();
|
||||
|
||||
@@ -30,7 +30,7 @@ public class ParamsUtil {
|
||||
public static Map< String, Object > getDynamicParams() {
|
||||
Map< String, Object > params = new ArrayMap();
|
||||
|
||||
final Map<String,Object> location = LocationHelper.getInstance().getLocationProperties();
|
||||
final Map< String, Object > location = LocationHelper.getInstance().getLocationProperties();
|
||||
if ( location != null ) {
|
||||
params.putAll( location );
|
||||
}
|
||||
@@ -71,7 +71,8 @@ public class ParamsUtil {
|
||||
public static Map< String, Object > getAnalyticsCustomParams() {
|
||||
Map< String, Object > map = new ArrayMap<>();
|
||||
map.put( "debug", DebugConfig.isDebug() ? 1 : 0 );
|
||||
map.put( "systemversion", Utils.getFotaVersion() );
|
||||
String fota = Utils.getFotaVersion();
|
||||
map.put( "systemversion", TextUtils.isEmpty( fota ) ? DebugConfig.getProductFlavor() : fota );
|
||||
map.put( "sn", Utils.getSn() );
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.mogo.commons.network;
|
||||
import com.mogo.commons.data.BaseData;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.RequestOptions;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
import com.mogo.utils.network.utils.Util;
|
||||
|
||||
import io.reactivex.Observer;
|
||||
|
||||
@@ -2,11 +2,17 @@ package com.mogo.commons.network;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.cdma.CdmaCellLocation;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.utils.storage.SharedPrefsMgr;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -55,10 +61,15 @@ 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() {
|
||||
|
||||
if ( DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_SELF_INNOVATE ) {
|
||||
return SharedPrefsMgr.getInstance( AbsMogoApplication.getApp() ).getString( "allocated_sn" );
|
||||
}
|
||||
return getSystemProperties( GSM_SERIAL );
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
GROUP=com.mogo.connection
|
||||
POM_ARTIFACT_ID=mogo-connection
|
||||
VERSION_CODE=1
|
||||
@@ -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
|
||||
* <p>
|
||||
* 描述
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">mogo-connection</string>
|
||||
</resources>
|
||||
@@ -1,5 +1,6 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
// buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
@@ -30,6 +31,7 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api rootProject.ext.dependencies.glide
|
||||
implementation rootProject.ext.dependencies.kotlinstdlibjdk7
|
||||
implementation rootProject.ext.dependencies.glideanno
|
||||
implementation rootProject.ext.dependencies.glideokhttp3
|
||||
implementation rootProject.ext.dependencies.supportannos
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#-----MogoUtils-----
|
||||
-keep class com.mogo.utils.network.CallerType
|
||||
-keep class com.mogo.utils.network.CallerRestrictTo
|
||||
-keep class com.mogo.utils.glide.GlideRoundedCornersTransform.CornerType
|
||||
-keep class com.mogo.utils.logger.LogLevel
|
||||
6
foudations/mogo-utils/proguard-rules.pro
vendored
@@ -19,3 +19,9 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----MogoUtils-----
|
||||
-keep class com.mogo.utils.network.CallerType
|
||||
-keep class com.mogo.utils.network.CallerRestrictTo
|
||||
-keep class com.mogo.utils.glide.GlideRoundedCornersTransform.CornerType
|
||||
-keep class com.mogo.utils.logger.LogLevel
|
||||
@@ -7,7 +7,7 @@ import java.util.concurrent.ThreadFactory;
|
||||
public class ThreadPoolService {
|
||||
|
||||
private static final ExecutorService SERVICE = Executors.newFixedThreadPool( 3, new ThreadFactoryImpl() );
|
||||
|
||||
private static final ExecutorService SINGLE_THREAD_SERVICE = Executors.newSingleThreadExecutor(new SingleThreadFactoryImpl());
|
||||
private static class ThreadFactoryImpl implements ThreadFactory {
|
||||
|
||||
private static int mCounter = 1;
|
||||
@@ -18,10 +18,26 @@ public class ThreadPoolService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单线程队列执行的ThreadFactory实现,应该只会new一个Thread
|
||||
*/
|
||||
private static class SingleThreadFactoryImpl implements ThreadFactory{
|
||||
private static int counter = 1;
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "SingleThread - " + counter++);
|
||||
}
|
||||
}
|
||||
|
||||
private ThreadPoolService() {
|
||||
}
|
||||
|
||||
public static void execute( Runnable task ) {
|
||||
SERVICE.execute( task );
|
||||
}
|
||||
|
||||
public static void singleExecute(Runnable task) {
|
||||
SINGLE_THREAD_SERVICE.execute(task);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
package com.mogo.utils.sqlite
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.mogo.utils.sqlite.annotation.DbField
|
||||
import com.mogo.utils.sqlite.annotation.DbTable
|
||||
import java.lang.reflect.Field
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* <p>数据类操作实现</p>
|
||||
*Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
//T必须指明上界是Any且不为null,下面会用到反射获取对象实例,默认是Any?
|
||||
open class BaseDao<T : Any> : IBaseDao<T> {
|
||||
|
||||
//数据库操作的引用
|
||||
private var sqLiteDatabase: SQLiteDatabase? = null
|
||||
//要操作的数据实体的引用
|
||||
private var entityClass: Class<T>? = null
|
||||
//要操作的数据表名称
|
||||
private var tableName: String? = null
|
||||
//记录数据表是否存在
|
||||
private var isInit = false
|
||||
|
||||
//因为反射会消耗时间,这里使用缓存,进行性能优化
|
||||
//缓存空间(key-字段名,标注的自定义注解 value-成员变量)
|
||||
private var cacheField: HashMap<String, Field>? = null
|
||||
|
||||
override fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean {
|
||||
this.sqLiteDatabase = sqLiteDatabase
|
||||
this.entityClass = entityClass
|
||||
//自动建表(只创建一次)
|
||||
if (!isInit) {
|
||||
//获取表名
|
||||
tableName = entityClass.getAnnotation(DbTable::class.java).tableName
|
||||
|
||||
//如果数据库没有建立连接跳出操作防止异常信息
|
||||
if (!sqLiteDatabase.isOpen) {
|
||||
return false
|
||||
}
|
||||
|
||||
//执行Sql进行自动建表
|
||||
val createTableSql = getCreateTableSql()
|
||||
sqLiteDatabase.execSQL(createTableSql)
|
||||
|
||||
//初始化缓存空间
|
||||
cacheField = HashMap()
|
||||
initCacheField()
|
||||
|
||||
//标记已经创建过数据表
|
||||
isInit = true
|
||||
}
|
||||
|
||||
return isInit
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化字段缓存
|
||||
*/
|
||||
private fun initCacheField() {
|
||||
//1.取到所有的列名(查询一个空表获取表结构,不影响性能)
|
||||
if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
|
||||
val sqlQuery = "select * from $tableName limit 1,0"
|
||||
val cursor = sqLiteDatabase!!.rawQuery(sqlQuery, null)
|
||||
//获取所有的列名
|
||||
val columnNames = cursor.columnNames
|
||||
//关闭资源
|
||||
cursor.close()
|
||||
//2.取所有成员名
|
||||
val columnFields = entityClass!!.declaredFields
|
||||
//3.通过两层循环,进行对应关系建立
|
||||
columnNames.forEach ColumnFor@{ columnName ->
|
||||
columnFields.forEach FieldFor@{ columnField ->
|
||||
if (columnName == columnField.getAnnotation(DbField::class.java).fieldName) {
|
||||
columnField.isAccessible = true
|
||||
cacheField!![columnName] = columnField
|
||||
}
|
||||
return@FieldFor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼装创建数据表的SQL语句
|
||||
*/
|
||||
private fun getCreateTableSql(): String? {
|
||||
//create table if not exists tb_name(_id integer,name varchar2(20))
|
||||
val sqlCreateTable = StringBuffer()
|
||||
sqlCreateTable.append("create table if not exists ")
|
||||
sqlCreateTable.append("$tableName (")
|
||||
//反射获取所有的数据对象内的成员变量
|
||||
val fields = entityClass!!.declaredFields
|
||||
|
||||
fields.forEachIndexed { index, field ->
|
||||
//字段名称
|
||||
val columnName = field.getAnnotation(DbField::class.java).fieldName
|
||||
//获取成员变量数据类型
|
||||
|
||||
when (val fieldType = field.type) {
|
||||
String::class.java -> {
|
||||
sqlCreateTable.append("$columnName TEXT,")
|
||||
}
|
||||
Integer::class.java -> {
|
||||
sqlCreateTable.append("$columnName INTEGER,")
|
||||
}
|
||||
Long::class.java -> {
|
||||
sqlCreateTable.append("$columnName BIGINT,")
|
||||
}
|
||||
Double::class.java -> {
|
||||
sqlCreateTable.append("$columnName DOUBLE,")
|
||||
}
|
||||
ByteArray::class.java -> {
|
||||
sqlCreateTable.append("$columnName BLOB,")
|
||||
}
|
||||
else -> {
|
||||
//未知类型
|
||||
throw UnsupportedOperationException("未定义的数据类型:fieldName= $columnName fieldType= $fieldType")
|
||||
}
|
||||
}
|
||||
|
||||
if (index == fields.size - 1) {
|
||||
if (sqlCreateTable.endsWith(","))
|
||||
sqlCreateTable.deleteCharAt(sqlCreateTable.length - 1)
|
||||
}
|
||||
}
|
||||
sqlCreateTable.append(")")
|
||||
|
||||
return sqlCreateTable.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
override fun insert(entity: T): Long {
|
||||
//1、准备好ContentValues中的数据
|
||||
//2、设置插入的内容
|
||||
val values: ContentValues = getContentValuesForInsert(entity)
|
||||
//3、执行插入
|
||||
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
|
||||
sqLiteDatabase!!.insert(tableName, null, values)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据
|
||||
*/
|
||||
override fun delete(where: T): Int {
|
||||
val condition = Condition(getContentValuesForQuery(where))
|
||||
|
||||
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
|
||||
//受影响行数
|
||||
sqLiteDatabase!!
|
||||
.delete(
|
||||
tableName,
|
||||
condition.getWhereCause(),
|
||||
condition.getWhereArgs()
|
||||
)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
*/
|
||||
override fun update(where: T, newEntity: T): Int {
|
||||
val condition = Condition(getContentValuesForQuery(where))
|
||||
|
||||
return if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
|
||||
//受影响行数
|
||||
sqLiteDatabase!!
|
||||
.update(
|
||||
tableName,
|
||||
getContentValuesForInsert(newEntity),
|
||||
condition.getWhereCause(),
|
||||
condition.getWhereArgs()
|
||||
)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
* @param where 查询条件对象,同时也用来初始化对象使用
|
||||
*/
|
||||
override fun query(where: T): MutableList<T> {
|
||||
return query(where, null, null, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
* @param where 查询条件对象
|
||||
* @param orderBy 排序规则
|
||||
* @param startIndex 开始的位置
|
||||
* @param limit 限制查询得到的数据个数
|
||||
*/
|
||||
fun query(where: T, orderBy: String?, startIndex: Int?, limit: Int?): MutableList<T> {
|
||||
//拼接分页语句
|
||||
var limitString: String? = null
|
||||
if (startIndex != null && limit != null) {
|
||||
limitString = "$startIndex,$limit"
|
||||
}
|
||||
|
||||
val condition = Condition(getContentValuesForQuery(where))
|
||||
|
||||
var cursor: Cursor? = null
|
||||
|
||||
//定义查询结果
|
||||
val result = mutableListOf<T>()
|
||||
if (sqLiteDatabase != null && sqLiteDatabase!!.isOpen) {
|
||||
try {
|
||||
//查询数据库
|
||||
cursor = sqLiteDatabase!!
|
||||
.query(
|
||||
tableName,
|
||||
null,
|
||||
condition.getWhereCause(),
|
||||
condition.getWhereArgs(),
|
||||
null,
|
||||
null,
|
||||
orderBy,
|
||||
limitString
|
||||
)
|
||||
//将查到结果添加到返回集合中
|
||||
result.addAll(getQueryResult(cursor, where))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询使用的ContentValues
|
||||
*/
|
||||
private fun getContentValuesForQuery(entity: T): ContentValues {
|
||||
val contentValues = ContentValues()
|
||||
try {
|
||||
cacheField!!.forEach {
|
||||
if (it.value.get(entity) == null) {
|
||||
return@forEach
|
||||
}
|
||||
contentValues.put(it.key, it.value.get(entity).toString())
|
||||
}
|
||||
} catch (e: IllegalAccessError) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return contentValues
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件拼接
|
||||
*/
|
||||
class Condition(whereContent: ContentValues) {
|
||||
/**
|
||||
* 条件拼接
|
||||
* _id=?&&name=?
|
||||
*/
|
||||
private var whereCause: String? = null
|
||||
|
||||
private var whereArgs: Array<String>? = null
|
||||
|
||||
//根据传入的contentValues转换成查询条件
|
||||
init {
|
||||
//记录后面填充到查询语句“?”上的数据参数
|
||||
val argList = mutableListOf<String>()
|
||||
//拼接查询语句
|
||||
val whereCaseSb = StringBuilder()
|
||||
|
||||
/**
|
||||
* 是为了链接下面的查询条件条件,也或者是替换没有查询条件的语句。
|
||||
* 比如:要把检索条件作为一个参数传递给SQL,
|
||||
* 那么,当这个检索语句不存在的话就可以给它赋值为1=1.
|
||||
* 这样就避免了SQL出错,也就可以把加条件的SQL和不加条件的SQL合二为一。
|
||||
*/
|
||||
whereCaseSb.append(" 1=1 ")
|
||||
|
||||
val keys = whereContent.keySet()
|
||||
val iterator = keys.iterator()
|
||||
|
||||
//因为使用了“1=1”,所以即便是这里没有任何数据拼接,也是可以正常
|
||||
while (iterator.hasNext()) {
|
||||
val key = iterator.next() as String
|
||||
val valueObject = whereContent.get(key)
|
||||
if (valueObject != null) {
|
||||
val value = valueObject as String
|
||||
//拼接查询条件语句
|
||||
//1:1 and _id=? and name=?
|
||||
whereCaseSb.append(" and $key =?")
|
||||
|
||||
//记录?对应的value
|
||||
argList.add(value)
|
||||
}
|
||||
}
|
||||
//集合转成数组
|
||||
this.whereArgs = argList.toTypedArray()
|
||||
this.whereCause = whereCaseSb.toString()
|
||||
}
|
||||
|
||||
fun getWhereCause(): String {
|
||||
return this.whereCause!!
|
||||
}
|
||||
|
||||
fun getWhereArgs(): Array<String> {
|
||||
return this.whereArgs!!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询db结果
|
||||
*/
|
||||
private fun getQueryResult(cursor: Cursor, where: T): MutableList<T> {
|
||||
//定义查询结果
|
||||
val result = mutableListOf<T>()
|
||||
//Cursor从头读到尾
|
||||
//游标从头读到尾
|
||||
cursor.moveToFirst()
|
||||
//移动游标获取下一行数据
|
||||
while (!cursor.isAfterLast) {
|
||||
//通过反射构建一个查询结果对象
|
||||
val item = where.javaClass.newInstance()
|
||||
|
||||
//拿到缓存的当前数据对象的成员变量与数据库的键值关系
|
||||
val fieldIterator = cacheField!!.entries.iterator()
|
||||
fieldIterator.forEach IteratorFor@{
|
||||
//获取数据库字段名称
|
||||
val columnName = it.key
|
||||
//数据库字段名对应的数据对象的成员变量
|
||||
val field = it.value
|
||||
//获取指定列名对应的索引
|
||||
val columnIndex = cursor.getColumnIndex(columnName)
|
||||
//获取成员变量数据类型
|
||||
val fieldType = field.type
|
||||
|
||||
if (columnIndex != -1) {
|
||||
when (fieldType) {
|
||||
String::class.java -> {
|
||||
field.set(item, cursor.getString(columnIndex))
|
||||
}
|
||||
Integer::class.java -> {
|
||||
field.set(item, cursor.getInt(columnIndex))
|
||||
}
|
||||
Long::class.java -> {
|
||||
field.set(item, cursor.getLong(columnIndex))
|
||||
}
|
||||
Double::class.java -> {
|
||||
field.set(item, cursor.getDouble(columnIndex))
|
||||
}
|
||||
ByteArray::class.java -> {
|
||||
field.set(item, cursor.getBlob(columnIndex))
|
||||
}
|
||||
else -> {
|
||||
//未知类型
|
||||
throw UnsupportedOperationException("未定义的数据类型:columnName= $columnName fieldType= $fieldType")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//添加到结果集
|
||||
result.add(item)
|
||||
//移动到下一个位置
|
||||
cursor.moveToNext()
|
||||
}
|
||||
cursor.close()
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插入使用的ContentValues
|
||||
*/
|
||||
private fun getContentValuesForInsert(entity: T): ContentValues {
|
||||
val contentValues = ContentValues()
|
||||
|
||||
val fieldIterator = cacheField!!.entries.iterator()
|
||||
|
||||
fieldIterator.forEach IteratorFor@{
|
||||
try {
|
||||
//获取变量的值
|
||||
val valueObject = it.value.get(entity) ?: return@IteratorFor
|
||||
//获取列名
|
||||
val columnName = it.key
|
||||
//获取成员变量数据类型
|
||||
val fieldType = it.value.type
|
||||
when (fieldType) {
|
||||
String::class.java -> {
|
||||
contentValues.put(columnName, valueObject as String)
|
||||
}
|
||||
Integer::class.java -> {
|
||||
contentValues.put(columnName, valueObject as Int)
|
||||
}
|
||||
Long::class.java -> {
|
||||
contentValues.put(columnName, valueObject as Long)
|
||||
}
|
||||
Double::class.java -> {
|
||||
contentValues.put(columnName, valueObject as Double)
|
||||
}
|
||||
ByteArray::class.java -> {
|
||||
contentValues.put(columnName, valueObject as ByteArray)
|
||||
}
|
||||
else -> {
|
||||
//未知类型
|
||||
throw UnsupportedOperationException("未定义的数据类型:columnName= $columnName fieldType= $fieldType")
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
return contentValues
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.mogo.utils.sqlite
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.mogo.utils.sqlite.annotation.DbDatabase
|
||||
import com.mogo.utils.sqlite.proxy.BaseDaoProxyLog
|
||||
|
||||
|
||||
/**
|
||||
* <p>数据库处理工厂</p>
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
open class BaseDaoFactory {
|
||||
|
||||
//默认数据库名称
|
||||
private var dbName = "MoGoSQLite.db"
|
||||
|
||||
companion object {
|
||||
//单利工厂
|
||||
private var baseDaoFactory: BaseDaoFactory? = null
|
||||
|
||||
//数据库存储路径
|
||||
private lateinit var sqLiteDatabasePath: String
|
||||
|
||||
//数据库操作类
|
||||
private var sqLiteDatabase: SQLiteDatabase? = null
|
||||
|
||||
fun getInstance(): BaseDaoFactory {
|
||||
if (baseDaoFactory == null) {
|
||||
synchronized(BaseDaoFactory::class.java) {
|
||||
if (baseDaoFactory == null) {
|
||||
baseDaoFactory = BaseDaoFactory()
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseDaoFactory!!
|
||||
}
|
||||
}
|
||||
|
||||
//获取数据库操作对象
|
||||
fun <T : Any> getBaseDao(context: Context, entityClass: Class<T>): IBaseDao<T>? {
|
||||
var baseDao: IBaseDao<T>? = null
|
||||
|
||||
try {
|
||||
//获取数据库名称,如果没有设置则使用默认名称
|
||||
val dbDatabase = entityClass.getAnnotation(DbDatabase::class.java)
|
||||
if (dbDatabase != null) {
|
||||
dbName = dbDatabase.dbName
|
||||
}
|
||||
//openOrCreateDatabase 如果不存在则先创建再打开数据库,如果存在则直接打开。
|
||||
sqLiteDatabasePath =
|
||||
"${context.getDir("database", Context.MODE_APPEND).path}/$dbName"
|
||||
sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqLiteDatabasePath, null)
|
||||
|
||||
// 这里为了演示,添加了日志工具的叠加使用,根据需要可以自己修改
|
||||
// baseDao = BaseDaoProxyShow().bind(BaseDaoProxyLog().bind(BaseDao<T>())) as IBaseDao<T>
|
||||
baseDao = BaseDaoProxyLog().bind(BaseDao<T>()) as IBaseDao<T>
|
||||
|
||||
baseDao.init(sqLiteDatabase!!, entityClass)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return baseDao
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
*/
|
||||
fun closeDatabase() {
|
||||
sqLiteDatabase?.close()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.mogo.utils.sqlite
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* <p>操作SQLite数据库的顶层接口</p>
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
interface IBaseDao<T> {
|
||||
/**
|
||||
* 初始化数据库连接
|
||||
*/
|
||||
fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean
|
||||
|
||||
/**
|
||||
* 将 [entity] 进行数据插入
|
||||
*/
|
||||
fun insert(entity: T): Long
|
||||
|
||||
/**
|
||||
* 根据条件 [where] 进行数据删除
|
||||
*/
|
||||
fun delete(where: T): Int
|
||||
|
||||
/**
|
||||
* 根据条件 [where] 进行数据更新,如果[where]==null 则代表删除所有数据
|
||||
*/
|
||||
fun update(where: T, newEntity: T): Int
|
||||
|
||||
/**
|
||||
* 根据条件 [where] 进行数据查询,如果[where]==null 则代表查询所有数据
|
||||
*/
|
||||
fun query(where: T): MutableList<T>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mogo.utils.sqlite.annotation
|
||||
|
||||
|
||||
/**
|
||||
* <p>添加在要操作的数据对象名上面,用来设置数据库名称</p>
|
||||
*
|
||||
* /**
|
||||
* * @DbDatabase("AppSQLite.db")
|
||||
* * class UserEntity {}
|
||||
* */
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class DbDatabase(val dbName: String)
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.mogo.utils.sqlite.annotation
|
||||
|
||||
|
||||
/**
|
||||
* <p>添加在要处理的数据对象的字段之上,用来设置数据表的字段名称</p>
|
||||
* /**
|
||||
* *@DbTable("tb_user")
|
||||
* *class UserEntity {
|
||||
* * @DbField("_id")
|
||||
* * var id: Int = 0
|
||||
* * @DbField("name")
|
||||
* * var name: String? = null
|
||||
* * @DbField("password")
|
||||
* * var password: String? = null
|
||||
* *}
|
||||
* */
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class DbField(val fieldName: String)
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mogo.utils.sqlite.annotation
|
||||
|
||||
|
||||
/**
|
||||
* <p>添加在要操作的数据对象名上面,用来设置数据表名称</p>
|
||||
*
|
||||
* /**
|
||||
* * @DbTable("tb_user")
|
||||
* * class UserEntity {}
|
||||
* */
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class DbTable(val tableName: String)
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.mogo.utils.sqlite.proxy
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.util.Log
|
||||
import com.mogo.utils.sqlite.IBaseDao
|
||||
|
||||
/**
|
||||
* <p>静态代理数据库操作类,用来记录日志</P>
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
class BaseDaoProxy<T>(var iBaseDao: IBaseDao<T>) : IBaseDao<T> by iBaseDao {
|
||||
override fun init(sqLiteDatabase: SQLiteDatabase, entityClass: Class<T>): Boolean {
|
||||
Log.i("数据库代理", "初始化数据库连接……")
|
||||
val isInitSuccess = iBaseDao.init(sqLiteDatabase, entityClass)
|
||||
if (isInitSuccess) {
|
||||
Log.i("数据库代理", "数据库连接成功……")
|
||||
} else {
|
||||
Log.e("数据库代理", "数据库连接失败……")
|
||||
}
|
||||
return isInitSuccess
|
||||
}
|
||||
|
||||
override fun insert(entity: T): Long {
|
||||
Log.i("数据库代理", "开始插入数据……")
|
||||
val result = iBaseDao.insert(entity)
|
||||
Log.i("数据库代理", "插入数据索引位置> $result <……")
|
||||
return result
|
||||
}
|
||||
|
||||
override fun delete(where: T): Int {
|
||||
Log.i("数据库代理", "开始删除数据……")
|
||||
val result = iBaseDao.delete(where)
|
||||
Log.i("数据库代理", "删除了> $result <条数据……")
|
||||
return result
|
||||
}
|
||||
|
||||
override fun update(where: T, newEntity: T): Int {
|
||||
Log.i("数据库代理", "开始更新数据……")
|
||||
val result = iBaseDao.update(where, newEntity)
|
||||
Log.i("数据库代理", "更新了> $result <条数据……")
|
||||
return result
|
||||
}
|
||||
|
||||
override fun query(where: T): MutableList<T> {
|
||||
Log.i("数据库代理", "开始查询数据……")
|
||||
val result = iBaseDao.query(where)
|
||||
Log.i("数据库代理", "查询到> ${result.size} <条数据……")
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.mogo.utils.sqlite.proxy
|
||||
|
||||
import android.util.Log
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* 使用java实现动态代理数据库操作类加入日志功能
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
|
||||
class BaseDaoProxyLog : InvocationHandler {
|
||||
|
||||
private var target: Any? = null
|
||||
|
||||
/**
|
||||
* 绑定委托对象并返回一个【代理占位】
|
||||
*
|
||||
* @param target 真实对象
|
||||
* @return 代理对象【占位】
|
||||
*/
|
||||
fun bind(target: Any): Any {
|
||||
this.target = target
|
||||
//取得代理对象
|
||||
return Proxy.newProxyInstance(
|
||||
target.javaClass.classLoader,
|
||||
target.javaClass.interfaces, this
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 同过代理对象调用方法首先进入这个方法.
|
||||
*
|
||||
* @param proxy --代理对象
|
||||
* @param method -- 方法,被调用方法.
|
||||
* @param args -- 方法的参数
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
var result: Any? = null
|
||||
//反射方法前调用
|
||||
Log.i("数据库代理", "当前执行>>${method.name}")
|
||||
//反射执行方法 相当于调用target.sayHelllo;
|
||||
result = method.invoke(target, *args)
|
||||
//反射方法后调用.
|
||||
Log.i("数据库代理", "执行结果>>$result")
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.mogo.utils.sqlite.proxy
|
||||
|
||||
import android.util.Log
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* 使用java实现动态代理数据库操作类,加入更多额外的功能,来测试代理类的叠加功能
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
class BaseDaoProxyShow : InvocationHandler {
|
||||
|
||||
private var target: Any? = null
|
||||
|
||||
/**
|
||||
* 绑定委托对象并返回一个【代理占位】
|
||||
*
|
||||
* @param target 真实对象
|
||||
* @return 代理对象【占位】
|
||||
*/
|
||||
fun bind(target: Any): Any {
|
||||
this.target = target
|
||||
//取得代理对象
|
||||
return Proxy.newProxyInstance(
|
||||
target.javaClass.classLoader,
|
||||
target.javaClass.interfaces, this
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 同过代理对象调用方法首先进入这个方法.
|
||||
*
|
||||
* @param proxy --代理对象
|
||||
* @param method -- 方法,被调用方法.
|
||||
* @param args -- 方法的参数
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
var result: Any? = null
|
||||
//反射方法前调用
|
||||
Log.i("数据库代理", "显示执行>>${method.name}")
|
||||
//反射执行方法 相当于调用target.sayHelllo;
|
||||
result = method.invoke(target, *args)
|
||||
//反射方法后调用.
|
||||
Log.i("数据库代理", "执行结果>>$result")
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,8 @@
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
#org.gradle.jvmargs=-Xmx1536m
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
@@ -17,6 +18,7 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
## maven 配置
|
||||
RELEASE_REPOSITORY_URL=http://nexus.zhidaoauto.com/repository/maven-releases/
|
||||
@@ -27,51 +29,51 @@ PASSWORD=xintai2018
|
||||
RELEASE=false
|
||||
# 模块版本
|
||||
## 工程内模块
|
||||
MOGO_COMMONS_VERSION=1.2.1.9
|
||||
MOGO_UTILS_VERSION=1.2.1.9
|
||||
MAP_AMAP_VERSION=1.2.1.9
|
||||
MAP_AUTONAVI_VERSION=1.2.1.9
|
||||
MOGO_MAP_VERSION=1.2.1.9
|
||||
MOGO_MAP_API_VERSION=1.2.1.9
|
||||
MOGO_SERVICE_VERSION=1.2.1.9
|
||||
MOGO_SERVICE_API_VERSION=1.2.1.9
|
||||
MOGO_CONNECTION_VERSION=1.2.1.9
|
||||
MOGO_MODULE_APPS_VERSION=1.2.1.9
|
||||
MOGO_MODULE_NAVI_VERSION=1.2.1.9
|
||||
MOGO_MODULE_SHARE_VERSION=1.2.1.18
|
||||
MOGO_MODULE_COMMON_VERSION=1.2.1.9
|
||||
MOGO_MODULE_MAIN_VERSION=1.2.1.9
|
||||
MOGO_MODULE_MAP_VERSION=1.2.1.9
|
||||
MOGO_MODULE_SERVICE_VERSION=1.2.1.9
|
||||
MOGO_MODULE_EXTENSIONS_VERSION=1.2.1.9
|
||||
MOGO_MODULE_SEARCH_VERSION=1.2.1.9
|
||||
MOGO_MODULE_BACK_VERSION=1.2.1.9
|
||||
MOGO_MODULE_GPS_SIMULATOR_VERSION=1.2.1.9
|
||||
MOGO_MODULE_GPS_SIMULATOR_DEBUG_VERSION=1.2.1.9
|
||||
MOGO_MODULE_GPS_SIMULATOR_NOOP_VERSION=1.2.1.9
|
||||
MOGO_MODULE_AUTHORIZE_VERSION=1.2.1.9
|
||||
MOGO_MODULE_GUIDE_VERSION=1.2.1.9
|
||||
MOGO_MODULE_MEDIA_VERSION=1.2.1.9
|
||||
|
||||
MOGO_MODULE_MAIN_LAUNCHER_VERSION = 1.2.1.9
|
||||
MOGO_MODULE_MAIN_INDEPENDENT_VERSION = 1.2.1.9
|
||||
|
||||
MOGO_COMMONS_VERSION=1.2.1.22
|
||||
MOGO_UTILS_VERSION=1.2.1.22
|
||||
MAP_AMAP_VERSION=1.2.1.22
|
||||
MAP_AUTONAVI_VERSION=1.2.1.22
|
||||
MOGO_MAP_VERSION=1.2.1.22
|
||||
MOGO_MAP_API_VERSION=1.2.1.22
|
||||
MOGO_SERVICE_VERSION=1.2.1.22
|
||||
MOGO_SERVICE_API_VERSION=1.2.1.22
|
||||
MOGO_CONNECTION_VERSION=1.2.1.22
|
||||
MOGO_MODULE_APPS_VERSION=1.2.1.22
|
||||
MOGO_MODULE_NAVI_VERSION=1.2.1.22
|
||||
MOGO_MODULE_SHARE_VERSION=1.2.1.22
|
||||
MOGO_MODULE_COMMON_VERSION=1.2.1.22
|
||||
MOGO_MODULE_MAIN_VERSION=1.2.1.22
|
||||
MOGO_MODULE_MAP_VERSION=1.2.1.22
|
||||
MOGO_MODULE_SERVICE_VERSION=1.2.1.22
|
||||
MOGO_MODULE_EXTENSIONS_VERSION=1.2.1.22
|
||||
MOGO_MODULE_SEARCH_VERSION=1.2.1.22
|
||||
MOGO_MODULE_BACK_VERSION=1.2.1.22
|
||||
MOGO_MODULE_GPS_SIMULATOR_VERSION=1.2.1.22
|
||||
MOGO_MODULE_GPS_SIMULATOR_DEBUG_VERSION=1.2.1.22
|
||||
MOGO_MODULE_GPS_SIMULATOR_NOOP_VERSION=1.2.1.22
|
||||
MOGO_MODULE_AUTHORIZE_VERSION=1.2.1.22
|
||||
MOGO_MODULE_GUIDE_VERSION=1.2.1.22
|
||||
MOGO_MODULE_MEDIA_VERSION=1.2.1.22
|
||||
MOGO_MODULE_MAIN_LAUNCHER_VERSION = 1.2.1.22
|
||||
MOGO_MODULE_MAIN_INDEPENDENT_VERSION = 1.2.1.22
|
||||
MOGO_MODULE_V2X_VERSION=1.2.1.22
|
||||
# 基础服务实现:passport、socket、location
|
||||
MOGO_BASE_SERVICES_APK_VERSION = 1.2.1.22
|
||||
MOGO_BASE_SERVICES_SDK_VERSION = 1.2.1.22
|
||||
|
||||
## 工程外部模块
|
||||
# 探路
|
||||
MOGO_MODULE_TANLU_VERSION=1.2.1.15
|
||||
MOGO_MODULE_TANLU_VERSION=1.3.1.20
|
||||
# 车聊聊
|
||||
CARCHATTING_VERSION=1.4.6
|
||||
CARCHATTING_VERSION=1.4.8
|
||||
# 车聊聊接口
|
||||
CARCHATTINGPROVIDER_VERSION=1.2.0
|
||||
CARCHATTINGPROVIDER_VERSION=1.3.4
|
||||
# 视频引导
|
||||
MOGO_MODULE_GUIDESHOW_VERSION=1.0.2-SNAPSHOT
|
||||
# 视频引导接口
|
||||
MOGO_MODULE_GUIDESHOW_PROVIDER_VERSION=1.0.2-SNAPSHOT
|
||||
# 在线车辆F
|
||||
MOGO_MODULE_ONLINECAR_VERSION=1.0.3.2
|
||||
# v2x
|
||||
MOGO_MODULE_V2X_VERSION=1.1.534
|
||||
# 推送
|
||||
MOGO_MODULE_PUSH_VERSION=1.1.5.7
|
||||
MOGO_MODULE_PUSH_BASE_VERSION=1.1.5.5
|
||||
@@ -79,13 +81,25 @@ MOGO_MODULE_PUSH_NOOP_VERSION=1.1.5.6
|
||||
# 广告资源位
|
||||
MOGO_MODULE_AD_CARD_VERSION=1.0.1
|
||||
# 探路上报和分享模块
|
||||
TANLULIB_VERSION=1.2.1.15
|
||||
TANLULIB_VERSION=1.3.1.20
|
||||
MOGO_MODULE_EVENT_PANEL_VERSION = 1.0.0-SNAPSHOT
|
||||
MOGO_MODULE_EVENT_PANEL_NOOP_VERSION = 1.0.0-SNAPSHOT
|
||||
#左侧面板模块
|
||||
MOGO_MODULE_LEFT_PANEL_VERSION = 1.2.1.10-SNAPSHOT
|
||||
MOGO_MODULE_LEFT_PANEL_NOOP_VERSION = 1.2.1.10-SNAPSHOT
|
||||
|
||||
# Boost分包
|
||||
BOOST_MULTIDEX_VERSION=1.0.0
|
||||
# hook ARouter分包实现
|
||||
HOOKPLUGIN_VERSION=1.0.0
|
||||
|
||||
# obu
|
||||
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
|
||||
|
||||
## 产品库必备配置
|
||||
applicationId=com.mogo.launcer
|
||||
applicationName=IntelligentPilot
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#-----library-MapAMap-----
|
||||
-keep class com.mogo.map.impl.amap.hook.BnHooker.*{*;}
|
||||
-keep class com.mogo.map.impl.amap.marker.CombineMovingPointOverlay.Status
|
||||
-keep class com.mogo.map.impl.amap.navi.PathPlanningErrorCodeConstants
|
||||
-keep class com.mogo.map.impl.amap.utils.MapStyleUtils.ColorEnum
|
||||
6
libraries/map-amap/proguard-rules.pro
vendored
@@ -19,3 +19,9 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----library-MapAMap-----
|
||||
-keep class com.mogo.map.impl.amap.hook.BnHooker.*{*;}
|
||||
-keep class com.mogo.map.impl.amap.marker.CombineMovingPointOverlay.Status
|
||||
-keep class com.mogo.map.impl.amap.navi.PathPlanningErrorCodeConstants
|
||||
-keep class com.mogo.map.impl.amap.utils.MapStyleUtils.ColorEnum
|
||||
@@ -321,6 +321,7 @@ public class AMapNaviViewWrapper implements IMogoMapView,
|
||||
@Override
|
||||
public void onNaviMapMode( int mode ) {
|
||||
Logger.i( TAG, "mode=" + mode );
|
||||
MogoMapListenerHandler.getInstance().onMapModeChanged( mode == 0 ? EnumMapUI.CarUp_2D : EnumMapUI.NorthUP_2D );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,7 +10,9 @@ import com.amap.api.maps.model.BitmapDescriptorFactory;
|
||||
import com.amap.api.maps.model.LatLng;
|
||||
import com.amap.api.maps.model.Marker;
|
||||
import com.amap.api.maps.model.MarkerOptions;
|
||||
import com.amap.api.maps.model.animation.AlphaAnimation;
|
||||
import com.amap.api.maps.model.animation.Animation;
|
||||
import com.amap.api.maps.model.animation.AnimationSet;
|
||||
import com.amap.api.maps.model.animation.ScaleAnimation;
|
||||
import com.amap.api.maps.model.animation.TranslateAnimation;
|
||||
import com.amap.api.maps.utils.overlay.MovingPointOverlay;
|
||||
@@ -382,6 +384,47 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer {
|
||||
mMarker.startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScaleAnimationWithAlpha( float fromX, float toX, float fromY, float toY, float fromAlpha, float toAlpha, int duration, Interpolator interpolator, OnMarkerAnimationListener listener ) {
|
||||
if ( isDestroyed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScaleAnimation animationScale = new ScaleAnimation( fromX, toX, fromY, toY );
|
||||
animationScale.setFillMode( Animation.FILL_MODE_FORWARDS );
|
||||
|
||||
AlphaAnimation alphaAnimation = new AlphaAnimation( fromAlpha, toAlpha );
|
||||
alphaAnimation.setFillMode( Animation.FILL_MODE_FORWARDS );
|
||||
|
||||
AnimationSet animationSet = new AnimationSet( true );
|
||||
animationSet.setDuration( duration );
|
||||
animationSet.setInterpolator( interpolator);
|
||||
animationSet.setAnimationListener( new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart() {
|
||||
if ( isDestroyed() ) {
|
||||
return;
|
||||
}
|
||||
if ( listener != null ) {
|
||||
listener.onAnimStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
if ( isDestroyed() ) {
|
||||
return;
|
||||
}
|
||||
if ( listener != null ) {
|
||||
listener.onAnimEnd();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
mMarker.setAnimation( animationSet );
|
||||
mMarker.startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startJumpAnimation( float high, long duration, Interpolator interpolator, OnMarkerAnimationListener listener ) {
|
||||
if ( isDestroyed() || high <= 0.0f || interpolator == null || duration < 0 ) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
};
|
||||
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,2 @@
|
||||
#-----library-MapApi----
|
||||
-keep class com.mogo.map.**{*;}
|
||||
3
libraries/mogo-map-api/proguard-rules.pro
vendored
@@ -19,3 +19,6 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----library-MapApi----
|
||||
-keep class com.mogo.map.**{*;}
|
||||
@@ -267,9 +267,33 @@ public interface IMogoMarker {
|
||||
Interpolator interpolator,
|
||||
OnMarkerAnimationListener listener );
|
||||
|
||||
/**
|
||||
* 缩放动画
|
||||
*
|
||||
* @param fromX
|
||||
* @param toX
|
||||
* @param fromY
|
||||
* @param toY
|
||||
* @param fromAlpha
|
||||
* @param toAlpha
|
||||
* @param duration
|
||||
* @param interpolator
|
||||
* @param listener
|
||||
*/
|
||||
void startScaleAnimationWithAlpha( float fromX,
|
||||
float toX,
|
||||
float fromY,
|
||||
float toY,
|
||||
float fromAlpha,
|
||||
float toAlpha,
|
||||
int duration,
|
||||
Interpolator interpolator,
|
||||
OnMarkerAnimationListener listener );
|
||||
|
||||
|
||||
/**
|
||||
* 弹跳动画
|
||||
*
|
||||
* @param high
|
||||
* @param duration
|
||||
* @param interpolator
|
||||
@@ -278,7 +302,7 @@ public interface IMogoMarker {
|
||||
void startJumpAnimation( float high,
|
||||
long duration,
|
||||
Interpolator interpolator,
|
||||
OnMarkerAnimationListener listener);
|
||||
OnMarkerAnimationListener listener );
|
||||
|
||||
/**
|
||||
* 是否是否可点击
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,4 @@
|
||||
#-----MogoMap-----
|
||||
-keep class com.mogo.map.MogoNavi{
|
||||
private <init>();
|
||||
}
|
||||
5
libraries/mogo-map/proguard-rules.pro
vendored
@@ -19,3 +19,8 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----MogoMap-----
|
||||
-keep class com.mogo.map.MogoNavi{
|
||||
private <init>();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.module.main.MainActivity;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
|
||||
/**
|
||||
* 针对独立应用形式,做单独定制
|
||||
@@ -27,11 +31,7 @@ public class MainIndependentActivity extends MainActivity {
|
||||
FrameLayout.LayoutParams entranceParams = ( ( FrameLayout.LayoutParams ) mEntrance.getLayoutParams() );
|
||||
entranceParams.leftMargin = getResources().getDimensionPixelSize( R.dimen.module_main_entrance_fragment_container_marginLeft );
|
||||
mEntrance.setLayoutParams( entranceParams );
|
||||
|
||||
FrameLayout.LayoutParams headerParams = ( ( FrameLayout.LayoutParams ) mHeader.getLayoutParams() );
|
||||
headerParams.leftMargin = getResources().getDimensionPixelSize( R.dimen.module_main_header_fragment_container_marginLeft );
|
||||
mHeader.setLayoutParams( headerParams );
|
||||
|
||||
mLeftShadowFrame.setVisibility(View.VISIBLE);
|
||||
mApps.setVisibility( View.GONE );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="module_main_entrance_fragment_container_marginLeft">635px</dimen>
|
||||
<dimen name="module_main_header_fragment_container_marginLeft">366px</dimen>
|
||||
</resources>
|
||||
1
modules/mogo-module-apps/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# 应用列表 + Launcher 模式下的左侧导航按钮
|
||||
@@ -45,7 +45,6 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.material
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
implementation rootProject.ext.dependencies.androidxrecyclerview
|
||||
implementation rootProject.ext.dependencies.guideshowprovider
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
implementation rootProject.ext.dependencies.mogomap
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#-----AppModule-----
|
||||
-keep class com.mogo.module.apps.model.AppEnum
|
||||
-keep class com.mogo.module.apps.view.**{*;}
|
||||
-keep class com.mogo.module.apps.AppFilter
|
||||
5
modules/mogo-module-apps/proguard-rules.pro
vendored
@@ -19,3 +19,8 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file mName.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
#-----AppModule-----
|
||||
-keep class com.mogo.module.apps.model.AppEnum
|
||||
-keep class com.mogo.module.apps.view.** {*;}
|
||||
-keep class com.mogo.module.apps.AppFilter
|
||||
|
||||
@@ -4,22 +4,10 @@ import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.map.location.IMogoLocationClient;
|
||||
import com.mogo.map.marker.IMogoMarkerManager;
|
||||
import com.mogo.map.navi.IMogoNavi;
|
||||
import com.mogo.map.uicontroller.IMogoMapUIController;
|
||||
import com.mogo.module.common.entity.MarkerResponse;
|
||||
import com.mogo.module.common.entity.MarkerShowEntity;
|
||||
import com.mogo.module.guideshow.provider.GuideShowProviderConstant;
|
||||
import com.mogo.module.guideshow.provider.IGuideShowProvider;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.service.analytics.IMogoAnalytics;
|
||||
import com.mogo.service.cardmanager.IMogoCardManager;
|
||||
import com.mogo.service.connection.IMogoSocketManager;
|
||||
import com.mogo.service.imageloader.IMogoImageloader;
|
||||
import com.mogo.service.map.IMogoMapService;
|
||||
import com.mogo.service.statusmanager.IMogoStatusManager;
|
||||
|
||||
/**
|
||||
* author : zyz
|
||||
@@ -35,13 +23,11 @@ public class AppServiceHandler {
|
||||
private static IMogoServiceApis mApis;
|
||||
private static IMogoCardManager mMogoCardManager;
|
||||
private static IMogoAnalytics mMogoAnalytics;
|
||||
private static IGuideShowProvider mMogoGuideShow;
|
||||
|
||||
public static void init( final Context context ) {
|
||||
mApis = ( IMogoServiceApis ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICE_APIS ).navigation( context );
|
||||
mMogoCardManager = mApis.getCardManagerApi();
|
||||
mMogoAnalytics = mApis.getAnalyticsApi();
|
||||
mMogoGuideShow = ( IGuideShowProvider ) ARouter.getInstance().build( GuideShowProviderConstant.GUIDE_SHOW_PROVIDER ).navigation( context );
|
||||
|
||||
}
|
||||
|
||||
@@ -53,10 +39,6 @@ public class AppServiceHandler {
|
||||
return mMogoAnalytics;
|
||||
}
|
||||
|
||||
public static IGuideShowProvider getMogoGuideShow() {
|
||||
return mMogoGuideShow;
|
||||
}
|
||||
|
||||
public static IMogoServiceApis getApis() {
|
||||
if ( mApis == null ) {
|
||||
mApis = ( IMogoServiceApis ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICE_APIS ).navigation( AbsMogoApplication.getApp() );
|
||||
|
||||
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 7.4 KiB |