Merge branch 'dev' into dev_custom_map
# Conflicts: # libraries/mogo-map/src/main/java/com/mogo/map/MogoNavi.java # modules/mogo-module-v2x/src/main/java/com/mogo/module/v2x/V2XModuleProvider.java
This commit is contained in:
3
.idea/dictionaries/admin.xml
generated
Normal file
3
.idea/dictionaries/admin.xml
generated
Normal file
@@ -0,0 +1,3 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="admin" />
|
||||
</component>
|
||||
7
.idea/gradle.xml
generated
7
.idea/gradle.xml
generated
@@ -22,6 +22,8 @@
|
||||
<option value="$PROJECT_DIR$/libraries/map-custom" />
|
||||
<option value="$PROJECT_DIR$/libraries/mogo-map" />
|
||||
<option value="$PROJECT_DIR$/libraries/mogo-map-api" />
|
||||
<option value="$PROJECT_DIR$/libraries/mogo-tanlu-api" />
|
||||
<option value="$PROJECT_DIR$/libraries/tanlulib" />
|
||||
<option value="$PROJECT_DIR$/main-extensions" />
|
||||
<option value="$PROJECT_DIR$/main-extensions/mogo-module-main-independent" />
|
||||
<option value="$PROJECT_DIR$/main-extensions/mogo-module-main-launcher" />
|
||||
@@ -30,8 +32,6 @@
|
||||
<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" />
|
||||
@@ -41,6 +41,7 @@
|
||||
<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-monitor" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-obu" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-push" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-push-base" />
|
||||
@@ -50,7 +51,9 @@
|
||||
<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-tanlu" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-v2x" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-module-widgets" />
|
||||
<option value="$PROJECT_DIR$/services" />
|
||||
<option value="$PROJECT_DIR$/services/mogo-service" />
|
||||
<option value="$PROJECT_DIR$/services/mogo-service-api" />
|
||||
|
||||
191
app/build.gradle
191
app/build.gradle
@@ -2,11 +2,9 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
// buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
@@ -72,73 +70,83 @@ android {
|
||||
independent {
|
||||
manifest.srcFile 'src/independent/AndroidManifest.xml'
|
||||
}
|
||||
e8xx{
|
||||
e8xx {
|
||||
manifest.srcFile 'src/e8xx/AndroidManifest.xml'
|
||||
}
|
||||
em4 {
|
||||
manifest.srcFile 'src/em4/AndroidManifest.xml'
|
||||
}
|
||||
f8xxLauncherOnlineRelease {
|
||||
manifest.srcFile 'src/f8xxLauncherOnlineRelease/AndroidManifest.xml'
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "product", "basic", "env"
|
||||
|
||||
productFlavors {
|
||||
//独立app
|
||||
independent{
|
||||
independent {
|
||||
dimension "basic"
|
||||
applicationId rootProject.ext.android.independentApplicationId
|
||||
// 是否启动位置服务
|
||||
buildConfigField 'boolean', 'LAUNCH_LOCATION_SERVICE', '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{
|
||||
launcher {
|
||||
dimension "basic"
|
||||
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{
|
||||
f8xx {
|
||||
applicationId rootProject.ext.android.fLauncherApplicationId
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'false'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'true'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.fLauncherAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// e系列,采用Launcher方案
|
||||
e8xx {
|
||||
applicationId rootProject.ext.android.launcherApplicationId
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'true'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonLauncherAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// 同上
|
||||
em4 {
|
||||
applicationId rootProject.ext.android.launcherApplicationId
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType','2'
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'true'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonLauncherAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// e系列-2+32,对标D系列2+32,采用独立app的形式
|
||||
em3 {
|
||||
applicationId rootProject.ext.android.independentApplicationId
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
@@ -146,9 +154,13 @@ android {
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'false'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonIndependentAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// e系列-1+16,对标D系列1+16,采用独立app形式
|
||||
em1 {
|
||||
applicationId rootProject.ext.android.independentApplicationId
|
||||
dimension "product"
|
||||
// 使用思必驰语音
|
||||
buildConfigField 'int', 'AIType', '2'
|
||||
@@ -156,36 +168,51 @@ android {
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'false'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonIndependentAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// d系列
|
||||
d8xx {
|
||||
applicationId rootProject.ext.android.independentApplicationId
|
||||
dimension "product"
|
||||
// 使用同行者语音
|
||||
buildConfigField 'int', 'AIType','1'
|
||||
buildConfigField 'int', 'AIType', '1'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'false'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonIndependentAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// d系列 1+16 版本
|
||||
d82x{
|
||||
d82x {
|
||||
applicationId rootProject.ext.android.independentApplicationId
|
||||
dimension "product"
|
||||
// 使用同行者语音
|
||||
buildConfigField 'int', 'AIType','1'
|
||||
buildConfigField 'int', 'AIType', '1'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'true'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '0'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'false'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.commonIndependentAmapApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'false'
|
||||
}
|
||||
// 比亚迪
|
||||
bydauto{
|
||||
bydauto {
|
||||
applicationId rootProject.ext.android.bydautoIndependentApplicationId
|
||||
dimension "product"
|
||||
// 不使用语音
|
||||
buildConfigField 'int', 'AIType','0'
|
||||
buildConfigField 'int', 'AIType', '0'
|
||||
buildConfigField 'boolean', 'AI_ASSIST_ACTIVE_STAUTS', 'false'
|
||||
// 车机类型,主要用于区分自研车机还是别人家的车机,其他车机,比亚迪定为1
|
||||
buildConfigField 'int', 'CAR_MACHINE_TYPE', '1'
|
||||
buildConfigField 'boolean', 'ROAD_EVENT_ANIMATED', 'true'
|
||||
manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.bydautoIndependentApiValue]
|
||||
// 是否使用高德sdk自定义导航
|
||||
buildConfigField 'boolean', 'USE_CUSTOM_NAVI', 'true'
|
||||
}
|
||||
qa {
|
||||
dimension "env"
|
||||
@@ -206,42 +233,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
def generateVersionCode() {
|
||||
String vn = rootProject.ext.android.versionName
|
||||
String[] versions = vn.split("\\.")
|
||||
if (versions.length == 3) {
|
||||
int num1 = Integer.valueOf(versions[0])
|
||||
int num2 = Integer.valueOf(versions[1])
|
||||
int num3 = Integer.valueOf(versions[2])
|
||||
if (num1 < 1 || num1 > 99){
|
||||
throw new GradleException("版本号必须定义为 x.y.z,x[1,99], y[0, 99], z[0, 99])")
|
||||
}
|
||||
if (num2 < 0 || num2 > 99){
|
||||
throw new GradleException("版本号必须定义为 x.y.z,x[1,99], y[0, 99], z[0, 99])")
|
||||
}
|
||||
if (num3 < 0 || num3 > 99){
|
||||
throw new GradleException("版本号必须定义为 x.y.z,x[1,99], y[0, 99], z[0, 99])")
|
||||
}
|
||||
StringBuilder builder = new StringBuilder()
|
||||
builder.append(num1)
|
||||
if( num2 > 9 ){
|
||||
builder.append(num2)
|
||||
} else {
|
||||
builder.append("0").append(num2)
|
||||
}
|
||||
if( num3 > 9 ){
|
||||
builder.append(num3)
|
||||
} else {
|
||||
builder.append("0").append(num3)
|
||||
}
|
||||
println("last versionCode ${builder}")
|
||||
return Integer.valueOf(builder.toString())
|
||||
} else {
|
||||
throw new GradleException("版本号必须定义为 x.y.z,x[1,99], y[0, 99], z[0, 99])")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
@@ -262,9 +253,7 @@ dependencies {
|
||||
|
||||
implementation rootProject.ext.dependencies.carcallprovider
|
||||
implementation rootProject.ext.dependencies.carcall
|
||||
implementation rootProject.ext.dependencies.moduletanlu, {
|
||||
exclude group: 'com.mogo.module', module: 'module-share'
|
||||
}
|
||||
|
||||
implementation rootProject.ext.dependencies.mogologlib
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
@@ -279,6 +268,13 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.moduleservice
|
||||
implementation rootProject.ext.dependencies.modulesplash
|
||||
implementation rootProject.ext.dependencies.moduleV2x
|
||||
implementation rootProject.ext.dependencies.moduletanlu, {
|
||||
exclude group: 'com.mogo.module', module: 'module-share'
|
||||
}
|
||||
implementation rootProject.ext.dependencies.moduletanluapi
|
||||
implementation rootProject.ext.dependencies.mogomonitor
|
||||
implementation rootProject.ext.dependencies.mogomodulewidgets
|
||||
implementation rootProject.ext.dependencies.mogomoduleback
|
||||
} else {
|
||||
launcherImplementation project(':main-extensions:mogo-module-main-launcher')
|
||||
independentImplementation project(':main-extensions:mogo-module-main-independent')
|
||||
@@ -290,22 +286,21 @@ dependencies {
|
||||
implementation project(':modules:mogo-module-service')
|
||||
implementation project(':modules:mogo-module-splash')
|
||||
implementation project(':modules:mogo-module-v2x')
|
||||
implementation project(':modules:mogo-module-tanlu'), {
|
||||
exclude group: 'com.mogo.module', module: 'module-share'
|
||||
}
|
||||
implementation project(':libraries:mogo-tanlu-api')
|
||||
implementation project(':modules:mogo-module-monitor')
|
||||
implementation project(':modules:mogo-module-widgets')
|
||||
implementation project(':modules:mogo-module-back')
|
||||
}
|
||||
|
||||
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 ->
|
||||
// variant.outputs.all { //这里修改apk文件名
|
||||
// outputFileName = "Launcher2.0_V${android.defaultConfig.versionName}_${getCurrentDate()}_${variant.name}_${getGitCommit()}.apk"
|
||||
// println outputFileName
|
||||
// }
|
||||
//}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
def buildTime = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08:00"))
|
||||
def flavor = variant.productFlavors.collect { it.name }.join('-')
|
||||
@@ -321,64 +316,4 @@ android.applicationVariants.all { variant ->
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getMonthAndDay() {
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("MMddHH")
|
||||
return sdf.format(new Date())
|
||||
}
|
||||
|
||||
def getCurrentDate() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss")
|
||||
return sdf.format(new Date())
|
||||
}
|
||||
|
||||
def getGitCommit() {
|
||||
def gitDir = new File("${new File("${rootDir}")}/.git")
|
||||
if (!gitDir.isDirectory()) {
|
||||
return 'non_git_build'
|
||||
}
|
||||
|
||||
def cmd = 'git log --pretty=format:%h -1'
|
||||
def gitCommit = cmd.execute().text.trim()
|
||||
|
||||
print gitCommit
|
||||
|
||||
def cmd2 = 'git status -s'
|
||||
def gitStatus = cmd2.execute().text.trim()
|
||||
|
||||
println '---------'
|
||||
|
||||
print gitStatus
|
||||
if (gitStatus != null && !gitStatus.isEmpty()) {
|
||||
return 'local-build'
|
||||
}
|
||||
|
||||
assert !gitCommit.isEmpty()
|
||||
gitCommit
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
|
||||
it.getTasks().iterator().forEachRemaining {
|
||||
def nameLowCase = it.name
|
||||
|
||||
if (nameLowCase.startsWith("assemble")
|
||||
&& nameLowCase.contains("Independent")
|
||||
&& (nameLowCase.endsWith("Debug") || nameLowCase.endsWith("Release"))) {
|
||||
it.group = "assembleIndependent"
|
||||
} else if (nameLowCase.startsWith("assemble")
|
||||
&& nameLowCase.contains("Launcher")
|
||||
&& (nameLowCase.endsWith("Debug") || nameLowCase.endsWith("Release"))) {
|
||||
it.group = "assembleLauncher"
|
||||
} else if (nameLowCase.startsWith("install")
|
||||
&& nameLowCase.contains("Independent")
|
||||
&& (nameLowCase.endsWith("Debug") || nameLowCase.endsWith("Release"))) {
|
||||
it.group = "installIndependent"
|
||||
} else if (nameLowCase.startsWith("install")
|
||||
&& nameLowCase.contains("Launcher")
|
||||
&& (nameLowCase.endsWith("Debug") || nameLowCase.endsWith("Release"))) {
|
||||
it.group = "installLauncher"
|
||||
}
|
||||
}
|
||||
}
|
||||
apply from: "./regroup.gradle"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// 道路事件操作面板
|
||||
|
||||
project.dependencies {
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
d8xxImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
|
||||
d82xImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
em1Implementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
bydautoImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
em4Implementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
e8xxImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
f8xxImplementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
em3Implementation rootProject.ext.dependencies.moduleventpanelnoop
|
||||
} else {
|
||||
d8xxImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
|
||||
d82xImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
em1Implementation project(':modules:mogo-module-event-panel-noop')
|
||||
bydautoImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
em4Implementation project(':modules:mogo-module-event-panel-noop')
|
||||
e8xxImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
f8xxImplementation project(':modules:mogo-module-event-panel-noop')
|
||||
em3Implementation project(':modules:mogo-module-event-panel-noop')
|
||||
}
|
||||
}
|
||||
45
app/regroup.gradle
Normal file
45
app/regroup.gradle
Normal file
@@ -0,0 +1,45 @@
|
||||
// 将 install 和 assemble 任务按功能分组
|
||||
|
||||
afterEvaluate {
|
||||
|
||||
def independent = ["em3", "em1", "d8xx", "d82x", "bydauto"]
|
||||
def launcher = ["f8xx", "em4"]
|
||||
|
||||
it.getTasks().iterator().forEachRemaining {
|
||||
def task = it
|
||||
def taskName = task.name
|
||||
if (taskName.startsWith("assemble")
|
||||
&& taskName.contains("Independent")
|
||||
&& (taskName.endsWith("Debug") || taskName.endsWith("Release"))) {
|
||||
independent.forEach {
|
||||
if( taskName.toLowerCase().contains(it) ){
|
||||
task.group = "assembleIndependent"
|
||||
}
|
||||
}
|
||||
} else if (taskName.startsWith("assemble")
|
||||
&& taskName.contains("Launcher")
|
||||
&& (taskName.endsWith("Debug") || taskName.endsWith("Release"))) {
|
||||
launcher.forEach {
|
||||
if( taskName.toLowerCase().contains(it) ){
|
||||
task.group = "assembleLauncher"
|
||||
}
|
||||
}
|
||||
} else if (taskName.startsWith("install")
|
||||
&& taskName.contains("Independent")
|
||||
&& (taskName.endsWith("Debug") || taskName.endsWith("Release"))) {
|
||||
independent.forEach {
|
||||
if( taskName.toLowerCase().contains(it) ){
|
||||
task.group = "installIndependent"
|
||||
}
|
||||
}
|
||||
} else if (taskName.startsWith("install")
|
||||
&& taskName.contains("Launcher")
|
||||
&& (taskName.endsWith("Debug") || taskName.endsWith("Release"))) {
|
||||
launcher.forEach {
|
||||
if( taskName.toLowerCase().contains(it) ){
|
||||
task.group = "installLauncher"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
app/src/f8xxLauncherOnlineRelease/AndroidManifest.xml
Normal file
6
app/src/f8xxLauncherOnlineRelease/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>
|
||||
@@ -12,10 +12,10 @@
|
||||
android:theme="@style/AppTheme.App"
|
||||
tools:replace="android:label">
|
||||
<!-- 高德地图 -->
|
||||
<meta-data
|
||||
tools:replace="android:value"
|
||||
android:name="com.amap.api.v2.apikey"
|
||||
android:value="1c3fbc5f5e183619ffb1e7bc01e6751f" />
|
||||
<!-- <meta-data-->
|
||||
<!-- tools:replace="android:value"-->
|
||||
<!-- android:name="com.amap.api.v2.apikey"-->
|
||||
<!-- android:value="1c3fbc5f5e183619ffb1e7bc01e6751f" />-->
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
<!-- android:authorities="com.zhidao.auto.personal.provider"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:exported="true" />-->
|
||||
<meta-data
|
||||
android:name="com.amap.api.v2.apikey"
|
||||
android:value="a36b9f7b086fa3951bb35338a5a06dd3"
|
||||
tools:replace="android:value" />
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="com.amap.api.v2.apikey"-->
|
||||
<!-- android:value="a36b9f7b086fa3951bb35338a5a06dd3"-->
|
||||
<!-- tools:replace="android:value" />-->
|
||||
<!-- 高德地图 -->
|
||||
</application>
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.App"
|
||||
tools:replace="android:label">
|
||||
<meta-data
|
||||
android:name="com.amap.api.v2.apikey"
|
||||
android:value="${AMAP_API_VALUE}" />
|
||||
<!--保活用-->
|
||||
<service
|
||||
android:name="com.zhidao.boot.persistent.lib.PersistentAliveService"
|
||||
|
||||
@@ -11,8 +11,8 @@ 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.back.BackToLauncherConst;
|
||||
import com.mogo.module.carchatting.card.CallChatConstant;
|
||||
import com.mogo.module.common.MogoModule;
|
||||
import com.mogo.module.common.MogoModulePaths;
|
||||
@@ -22,6 +22,7 @@ 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.module.widgets.MogoWidgetsProvider;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.service.passport.IMogoTicketCallback;
|
||||
@@ -29,8 +30,8 @@ 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;
|
||||
import com.zhidao.mogo.tanlu.api.TanluApiConst;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
@@ -57,23 +58,25 @@ public class MogoApplication extends AbsMogoApplication {
|
||||
// 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() ) {
|
||||
if ( DebugConfig.isLauncher() ) {
|
||||
MogoModulePaths.addModule( new MogoModule( BackToLauncherConst.MODULE_PATH, BackToLauncherConst.MODULE_NAME ) );
|
||||
MogoModulePaths.addModule( new MogoModule( MediaConstants.TAG, MediaConstants.MODULE_TYPE ) );
|
||||
} else {
|
||||
MogoModulePaths.addBaseModule( new MogoModule( MogoWidgetsProvider.PATH, MogoWidgetsProvider.NAME ) );
|
||||
}
|
||||
if(DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_BYD){
|
||||
if ( DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_BYD ) {
|
||||
MogoModulePaths.addModule( new MogoModule( CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME ) );
|
||||
}
|
||||
MogoModulePaths.addModule( new MogoModule( TanluApiConst.MODULE_PATH, TanluApiConst.MODULE_NAME ) );
|
||||
MogoModulePaths.addModule( new MogoModule( TanluConstants.TAG, TanluConstants.MODEL_NAME ) );
|
||||
MogoModulePaths.addModule( new MogoModule( MogoServicePaths.PATH_SHARE, "ShareControl" ) );
|
||||
|
||||
MogoModulePaths.addModule( new MogoModule( EventPanelConstants.PATH_NAME, EventPanelConstants.MODULE_NAME ) );
|
||||
MogoModulePaths.addModule( new MogoModule( LeftPanelConst.PATH_NAME, LeftPanelConst.MODULE_NAME ) );
|
||||
|
||||
MogoModulePaths.addBaseModule( new MogoModule( ServiceConst.PATH_REFRESH_STRATEGY, ServiceConst.PATH_REFRESH_STRATEGY ) );
|
||||
MogoModulePaths.addBaseModule( new MogoModule( V2XConst.PATH_V2X_UI, V2XConst.PATH_V2X_UI ) );
|
||||
MogoModulePaths.addBaseModule( new MogoModule( V2XConst.PATH_V2X_UI, V2XConst.MODULE_NAME ) );
|
||||
MogoModulePaths.addModule( new MogoModule( V2XConst.PATH_EVENT_PANEL, V2XConst.MODULE_NAME_EVENT_PANEL ) );
|
||||
MogoModulePaths.addModule( new MogoModule( PushUIConstants.PATH, PushUIConstants.NAME ) );
|
||||
MogoModulePaths.addModule(new MogoModule(MogoServicePaths.PATH_LOG_LIB, "LogLib"));
|
||||
|
||||
if ( !DebugConfig.isLauncher() ) {
|
||||
PersistentManager.getInstance().initManager( this );
|
||||
@@ -100,13 +103,13 @@ public class MogoApplication extends AbsMogoApplication {
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
prepareBaseService(2_000L);
|
||||
prepareBaseService( 2_000L );
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础服务:passport、location、socket
|
||||
*/
|
||||
private void prepareBaseService(long delay) {
|
||||
private void prepareBaseService( long delay ) {
|
||||
UiThreadHandler.postDelayed( () -> {
|
||||
final IMogoServiceApis apis = ARouter.getInstance().navigation( IMogoServiceApis.class );
|
||||
// 第三方平台的sn是服务端生成的,所以必须在返回后才能开启
|
||||
|
||||
@@ -4,12 +4,18 @@ 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",
|
||||
fLauncherApplicationId : "com.mogo.launcher.f",
|
||||
bydautoIndependentApplicationId: "com.mogo.launcher.app.bydauto",
|
||||
fLauncherAmapApiValue : "aa2c8a0547378ead2f9a37762d9dd179",
|
||||
bydautoIndependentApiValue : "b1e1d527b02a493913c50985827c943a",
|
||||
commonLauncherAmapApiValue : "a36b9f7b086fa3951bb35338a5a06dd3",
|
||||
commonIndependentAmapApiValue : "1c3fbc5f5e183619ffb1e7bc01e6751f",
|
||||
compileSdkVersion : 28,
|
||||
buildToolsVersion : "29.0.2",
|
||||
minSdkVersion : 19,
|
||||
targetSdkVersion : 22,
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
@@ -21,6 +27,7 @@ targetSdkVersion : 22,
|
||||
androidxviewpager2 : "androidx.viewpager2:viewpager2:1.0.0",
|
||||
androidxrecyclerview : "androidx.recyclerview:recyclerview:1.1.0",
|
||||
androidxcardview : "androidx.cardview:cardview:1.0.0",
|
||||
localbroadcastmanager : "androidx.localbroadcastmanager:localbroadcastmanager:1.0.0",
|
||||
// flexbox
|
||||
flexbox : 'com.google.android:flexbox:2.0.1',
|
||||
// 测试
|
||||
@@ -76,11 +83,12 @@ targetSdkVersion : 22,
|
||||
roomRxjava : "android.arch.persistence.room:rxjava2:1.1.1",
|
||||
|
||||
// material
|
||||
material : 'com.google.android.material:material:1.0.0',
|
||||
material : 'com.google.android.material:material:1.1.0',
|
||||
|
||||
|
||||
// modules
|
||||
moduletanlu : "com.mogo.module:module-tanlu:${MOGO_MODULE_TANLU_VERSION}",
|
||||
moduletanluapi : "com.mogo.module:module-tanlu-api:${MOGO_TANLU_API_VERSION}",
|
||||
moduleshare : "com.mogo.module:module-share:${MOGO_MODULE_SHARE_VERSION}",
|
||||
mogocommons : "com.mogo.commons:mogo-commons:${MOGO_COMMONS_VERSION}",
|
||||
mogoutils : "com.mogo.commons:mogo-utils:${MOGO_UTILS_VERSION}",
|
||||
@@ -141,6 +149,7 @@ targetSdkVersion : 22,
|
||||
videoarm64 : "com.shuyu:gsyVideoPlayer-arm64:7.1.2",
|
||||
videojava : "com.shuyu:gsyVideoPlayer-java:7.1.2",
|
||||
eventbus : "org.greenrobot:eventbus:3.1.1",
|
||||
videoprocessor : "com.zhidao.video:video-processor:1.0.2.1",
|
||||
|
||||
coroutinescore : "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1",
|
||||
coroutinesandroid : "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1",
|
||||
@@ -175,6 +184,8 @@ targetSdkVersion : 22,
|
||||
mogobaseserviceapk : "com.mogo.base:services-apk:${MOGO_BASE_SERVICES_APK_VERSION}",
|
||||
// loglib
|
||||
mogologlib : "com.mogo.module:module-loglib:${LOGLIB_VERSION}",
|
||||
// monitor
|
||||
mogomonitor : "com.mogo.module:module-monitor:${MOGO_MODULE_MONITOR_VERSION}",
|
||||
|
||||
// google
|
||||
googlezxing : "com.google.zxing:core:3.3.3",
|
||||
@@ -184,5 +195,8 @@ targetSdkVersion : 22,
|
||||
androidxroomruntime : "androidx.room:room-runtime:2.2.3",
|
||||
androidxroomcompiler : "androidx.room:room-compiler:2.2.3",
|
||||
androidxroomktx : "androidx.room:room-ktx:2.2.3",
|
||||
|
||||
//
|
||||
mogomodulewidgets : "com.mogo.module:module-widgets:${MOGO_MODULE_WIDGETS_VERSION}",
|
||||
]
|
||||
}
|
||||
@@ -37,8 +37,9 @@ public abstract class MvpFragment<V extends IView, P extends Presenter<V>> exten
|
||||
mRootView = inflater.inflate( getLayoutId(), container, false );
|
||||
} else {
|
||||
ViewGroup viewGroup = ( ViewGroup ) mRootView.getParent();
|
||||
if ( viewGroup != null )
|
||||
if ( viewGroup != null ) {
|
||||
viewGroup.removeView( mRootView );
|
||||
}
|
||||
}
|
||||
mRootView = inflater.inflate(getLayoutId(), container, false);
|
||||
return mRootView;
|
||||
@@ -82,6 +83,10 @@ public abstract class MvpFragment<V extends IView, P extends Presenter<V>> exten
|
||||
@NonNull
|
||||
protected abstract P createPresenter();
|
||||
|
||||
public P getPresenter() {
|
||||
return mPresenter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected <T extends View> T findViewById(int id) {
|
||||
if (mRootView == null) {
|
||||
|
||||
@@ -61,6 +61,7 @@ public class ParamsUtil {
|
||||
STATIC_PARAMS.put( ServerParam.DEVICE_ID, DeviceIdUtils.getDeviceId( AbsMogoApplication.getApp() ) );
|
||||
STATIC_PARAMS.put( ServerParam.IMEI, CommonUtils.getIMEI( AbsMogoApplication.getApp() ) );
|
||||
STATIC_PARAMS.put( ServerParam.IMSI, CommonUtils.getIMSI( AbsMogoApplication.getApp() ) );
|
||||
STATIC_PARAMS.put( ServerParam.FOTA_VERSION, Utils.getFotaVersion() );
|
||||
STATIC_PARAMS.put( ServerParam.END_POINT, ServerParam.END_POINT_CAR );
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ class ServerParam {
|
||||
public static final String SN = "sn";
|
||||
public static final String CHANNEL = "channel";
|
||||
|
||||
public static final String FOTA_VERSION = "fotaVersion";
|
||||
|
||||
public static final String USER_ID = "userId";
|
||||
public static final String FILE = "file";
|
||||
public static final String END_POINT = "endPoint";
|
||||
|
||||
@@ -57,4 +57,34 @@ public class AppUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isAppForeground( Context context ) {
|
||||
if ( context != null ) {
|
||||
ActivityManager activityManager = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
List< ActivityManager.RunningAppProcessInfo > processes = activityManager.getRunningAppProcesses();
|
||||
for ( ActivityManager.RunningAppProcessInfo processInfo : processes ) {
|
||||
if ( processInfo.processName.equals( context.getPackageName() ) ) {
|
||||
if ( processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isAppForeground( Context context, String pkg ) {
|
||||
if ( context != null ) {
|
||||
ActivityManager activityManager = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
List< ActivityManager.RunningAppProcessInfo > processes = activityManager.getRunningAppProcesses();
|
||||
for ( ActivityManager.RunningAppProcessInfo processInfo : processes ) {
|
||||
if ( processInfo.processName.equals( pkg ) ) {
|
||||
if ( processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,8 +443,8 @@ public class DateTimeUtils {
|
||||
* @param timestamp 时间戳
|
||||
* @return
|
||||
*/
|
||||
public static String getTimeText( long timestamp) {
|
||||
SimpleDateFormat format = new SimpleDateFormat(yyyy_Nian_MM_Yue_dd_Ri, Locale.US);
|
||||
public static String getTimeText( long timestamp, String dateFormat) {
|
||||
SimpleDateFormat format = new SimpleDateFormat(dateFormat, Locale.US);
|
||||
String strStart = format.format(new Date(timestamp));
|
||||
return strStart;
|
||||
}
|
||||
|
||||
@@ -1,432 +0,0 @@
|
||||
package com.mogo.utils.sqlite
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.mogo.utils.logger.Logger
|
||||
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 val TAG = "BaseDao"
|
||||
|
||||
//数据库操作的引用
|
||||
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()
|
||||
Logger.d(TAG, "执行SQL:$createTableSql")
|
||||
|
||||
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) {
|
||||
java.lang.String::class.java -> {
|
||||
sqlCreateTable.append("$columnName TEXT,")
|
||||
}
|
||||
java.lang.Integer::class.java -> {
|
||||
sqlCreateTable.append("$columnName INTEGER,")
|
||||
}
|
||||
java.lang.Long::class.java -> {
|
||||
sqlCreateTable.append("$columnName BIGINT,")
|
||||
}
|
||||
java.lang.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) {
|
||||
java.lang.String::class.java -> {
|
||||
field.set(item, cursor.getString(columnIndex))
|
||||
}
|
||||
java.lang.Integer::class.java -> {
|
||||
field.set(item, cursor.getInt(columnIndex))
|
||||
}
|
||||
java.lang.Long::class.java -> {
|
||||
field.set(item, cursor.getLong(columnIndex))
|
||||
}
|
||||
java.lang.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) {
|
||||
java.lang.String::class.java -> {
|
||||
contentValues.put(columnName, valueObject as String)
|
||||
}
|
||||
java.lang.Integer::class.java -> {
|
||||
contentValues.put(columnName, valueObject as Int)
|
||||
}
|
||||
java.lang.Long::class.java -> {
|
||||
contentValues.put(columnName, valueObject as Long)
|
||||
}
|
||||
java.lang.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()
|
||||
}
|
||||
}
|
||||
|
||||
Logger.d(TAG, "contentValues:$contentValues")
|
||||
|
||||
return contentValues
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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,488 @@
|
||||
package com.mogo.utils.sqlite;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.sqlite.annotation.DbField;
|
||||
import com.mogo.utils.sqlite.annotation.DbTable;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据库操作
|
||||
*
|
||||
* @param <T>
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class SQLBaseDao<T> implements SQLIDao<T> {
|
||||
private String TAG = "SQLBaseDao";
|
||||
|
||||
//数据库操作的引用
|
||||
private SQLiteDatabase sqLiteDatabase;
|
||||
//要操作的数据实体的引用
|
||||
private Class<T> entityClass;
|
||||
//要操作的数据表名称
|
||||
private String tableName;
|
||||
//记录数据表是否存在
|
||||
private boolean isInit = false;
|
||||
|
||||
//因为反射会消耗时间,这里使用缓存,进行性能优化
|
||||
//缓存空间(key-字段名,标注的自定义注解 value-成员变量)
|
||||
private HashMap<String, Field> cacheField;
|
||||
|
||||
@Override
|
||||
public boolean init(@NotNull SQLiteDatabase sqLiteDatabase, @NotNull Class<T> entityClass) {
|
||||
this.sqLiteDatabase = sqLiteDatabase;
|
||||
this.entityClass = entityClass;
|
||||
//自动建表(只创建一次)
|
||||
if (!isInit) {
|
||||
//获取表名
|
||||
tableName = entityClass.getAnnotation(DbTable.class).tableName();
|
||||
|
||||
//如果数据库没有建立连接跳出操作防止异常信息
|
||||
if (!sqLiteDatabase.isOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//执行Sql进行自动建表
|
||||
String createTableSql = getCreateTableSql();
|
||||
Logger.d(TAG, "执行SQL:" + createTableSql);
|
||||
sqLiteDatabase.execSQL(createTableSql);
|
||||
|
||||
//初始化缓存空间
|
||||
cacheField = new HashMap();
|
||||
initCacheField();
|
||||
|
||||
//标记已经创建过数据表
|
||||
isInit = true;
|
||||
}
|
||||
|
||||
return isInit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*
|
||||
* @param entity 要插入数据的数据对象爱你那个
|
||||
* @return 插入结果ID,如果发生错误则为-1
|
||||
*/
|
||||
@Override
|
||||
public long insert(T entity) {
|
||||
//1、准备好ContentValues中的数据
|
||||
//2、设置插入的内容
|
||||
ContentValues values = getContentValuesForInsert(entity);
|
||||
//3、执行插入
|
||||
long result;
|
||||
if (sqLiteDatabase != null && sqLiteDatabase.isOpen()) {
|
||||
result = sqLiteDatabase.insert(tableName, null, values);
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据
|
||||
*
|
||||
* @param where 要删除的对象,对象的字段如果赋值,则代表查询条件
|
||||
* @return 受影响行数
|
||||
*/
|
||||
@Override
|
||||
public int delete(T where) {
|
||||
// 拼接查询条件
|
||||
Condition condition = new Condition(getContentValuesForQuery(where));
|
||||
int result;
|
||||
if (sqLiteDatabase != null && sqLiteDatabase.isOpen()) {
|
||||
//受影响行数
|
||||
result = sqLiteDatabase.delete(
|
||||
tableName,
|
||||
condition.getWhereCause(),
|
||||
condition.getWhereArgs()
|
||||
);
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
*
|
||||
* @param where 要更新的对象,对象的字段如果赋值,则代表查询条件
|
||||
* @param newEntity 新的数据内容
|
||||
* @return 受影响行数
|
||||
*/
|
||||
@Override
|
||||
public int update(T where, T newEntity) {
|
||||
Condition condition = new Condition(getContentValuesForQuery(where));
|
||||
int result;
|
||||
if (sqLiteDatabase != null && sqLiteDatabase.isOpen()) {
|
||||
//受影响行数
|
||||
result = sqLiteDatabase.update(
|
||||
tableName,
|
||||
getContentValuesForInsert(newEntity),
|
||||
condition.getWhereCause(),
|
||||
condition.getWhereArgs()
|
||||
);
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*
|
||||
* @param where 查询条件对象,同时也用来初始化对象使用
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public List<T> query(T where) {
|
||||
return query(where, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*
|
||||
* @param where 查询条件对象,同时也用来初始化对象使用
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public List<T> query(T where, String orderBy) {
|
||||
return query(where, orderBy, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param where 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
|
||||
* @param orderBy 排序字段
|
||||
* @param isOrderDESC 是否倒序 true-倒序,false-正序
|
||||
* @return 结果集合
|
||||
*/
|
||||
@Override
|
||||
public List<T> query(T where, String orderBy, boolean isOrderDESC) {
|
||||
if (isOrderDESC) {
|
||||
orderBy = orderBy + " DESC";
|
||||
}
|
||||
return query(where, orderBy, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*
|
||||
* @param where 查询条件对象
|
||||
* @param orderBy 排序规则
|
||||
* @param startIndex 开始的位置
|
||||
* @param limit 限制查询得到的数据个数
|
||||
*/
|
||||
public ArrayList<T> query(T where, String orderBy, Integer startIndex, Integer limit) {
|
||||
//拼接分页语句
|
||||
String limitString = null;
|
||||
if (startIndex != null && limit != null) {
|
||||
limitString = startIndex + "," + limit;
|
||||
}
|
||||
Condition condition = new Condition(getContentValuesForQuery(where));
|
||||
Cursor cursor = null;
|
||||
//定义查询结果
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
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 (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询db结果
|
||||
*/
|
||||
private ArrayList<T> getQueryResult(Cursor cursor, T where) {
|
||||
//定义查询结果
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
//Cursor从头读到尾
|
||||
//游标从头读到尾
|
||||
cursor.moveToFirst();
|
||||
try {
|
||||
if (where != null) {
|
||||
//移动游标获取下一行数据
|
||||
while (!cursor.isAfterLast()) {
|
||||
//通过反射构建一个查询结果对象
|
||||
T item = (T) where.getClass().newInstance();
|
||||
Set<Map.Entry<String, Field>> fieldIterator = cacheField.entrySet();
|
||||
for (Map.Entry<String, Field> stringFieldEntry : fieldIterator) {
|
||||
//获取数据库字段名称
|
||||
String columnName = stringFieldEntry.getKey();
|
||||
//数据库字段名对应的数据对象的成员变量
|
||||
Field field = stringFieldEntry.getValue();
|
||||
//获取指定列名对应的索引
|
||||
int columnIndex = cursor.getColumnIndex(columnName);
|
||||
//获取成员变量数据类型
|
||||
Class fieldType = field.getType();
|
||||
if (columnIndex != -1) {
|
||||
if (fieldType == (String.class)) {
|
||||
field.set(item, cursor.getString(columnIndex));
|
||||
} else if (fieldType == (Integer.class)) {
|
||||
field.set(item, cursor.getInt(columnIndex));
|
||||
} else if (fieldType == (Long.class)) {
|
||||
field.set(item, cursor.getLong(columnIndex));
|
||||
} else if (fieldType == (Double.class)) {
|
||||
field.set(item, cursor.getDouble(columnIndex));
|
||||
} else if (fieldType == (Boolean.class)) {
|
||||
int value = cursor.getInt(columnIndex);
|
||||
if (value == 0) {
|
||||
field.set(item, false);
|
||||
} else {
|
||||
field.set(item, true);
|
||||
}
|
||||
} else if (fieldType == (byte[].class)) {
|
||||
field.set(item, cursor.getBlob(columnIndex));
|
||||
} else {
|
||||
//未知类型
|
||||
throw new UnsupportedOperationException("未定义的数据类型:fieldName= " + columnName + " fieldType= " + fieldType);
|
||||
}
|
||||
}
|
||||
}
|
||||
//添加到结果集
|
||||
result.add(item);
|
||||
//移动到下一个位置
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
cursor.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化字段缓存
|
||||
*/
|
||||
private void initCacheField() {
|
||||
//1.取到所有的列名(查询一个空表获取表结构,不影响性能)
|
||||
if (sqLiteDatabase != null && sqLiteDatabase.isOpen()) {
|
||||
String sqlQuery = "select * from " + tableName + " limit 1,0";
|
||||
Cursor cursor = sqLiteDatabase.rawQuery(sqlQuery, null);
|
||||
//获取所有的列名
|
||||
String[] columnNames = cursor.getColumnNames();
|
||||
//关闭资源
|
||||
cursor.close();
|
||||
//2.取所有成员名
|
||||
Field[] columnFields = entityClass.getDeclaredFields();
|
||||
//3.通过两层循环,进行对应关系建立
|
||||
for (String columnName : columnNames) {
|
||||
for (Field columnField : columnFields) {
|
||||
if (columnName.equals(columnField.getAnnotation(DbField.class).fieldName())) {
|
||||
columnField.setAccessible(true);
|
||||
cacheField.put(columnName, columnField);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼装创建数据表的SQL语句
|
||||
*/
|
||||
private String getCreateTableSql() {
|
||||
//create table if not exists tb_name(_id integer,name varchar2(20))
|
||||
StringBuffer sqlCreateTable = new StringBuffer();
|
||||
sqlCreateTable.append("create table if not exists ");
|
||||
sqlCreateTable.append(tableName + " (");
|
||||
//反射获取所有的数据对象内的成员变量
|
||||
Field[] fields = entityClass.getDeclaredFields();
|
||||
|
||||
for (int index = 0; index < fields.length; index++) {
|
||||
//字段名称
|
||||
String columnName = fields[index].getAnnotation(DbField.class).fieldName();
|
||||
//获取成员变量数据类型
|
||||
Class fieldType = fields[index].getType();
|
||||
|
||||
if (fieldType == (String.class)) {
|
||||
sqlCreateTable.append(columnName).append(" TEXT,");
|
||||
} else if (fieldType == (Integer.class)) {
|
||||
sqlCreateTable.append(columnName).append(" INTEGER,");
|
||||
} else if (fieldType == (Long.class)) {
|
||||
sqlCreateTable.append(columnName).append(" BIGINT,");
|
||||
} else if (fieldType == (Double.class)) {
|
||||
sqlCreateTable.append(columnName).append(" DOUBLE,");
|
||||
} else if (fieldType == (Boolean.class)) {
|
||||
sqlCreateTable.append(columnName).append(" INTEGER,");
|
||||
} else if (fieldType == (byte[].class)) {
|
||||
sqlCreateTable.append(columnName).append(" BLOB,");
|
||||
} else {
|
||||
//未知类型
|
||||
throw new UnsupportedOperationException("未定义的数据类型:fieldName= " + columnName + " fieldType= " + fieldType);
|
||||
}
|
||||
|
||||
if (index == fields.length - 1) {
|
||||
if (sqlCreateTable.toString().endsWith(",")) {
|
||||
sqlCreateTable.deleteCharAt(sqlCreateTable.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlCreateTable.append(")");
|
||||
return sqlCreateTable.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插入使用的ContentValues
|
||||
*/
|
||||
private ContentValues getContentValuesForInsert(T entity) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
Set<Map.Entry<String, Field>> fieldIterator = cacheField.entrySet();
|
||||
for (Map.Entry<String, Field> stringFieldEntry : fieldIterator) {
|
||||
try {
|
||||
//获取变量的值
|
||||
Object valueObject = stringFieldEntry.getValue().get(entity);
|
||||
//获取列名
|
||||
String columnName = stringFieldEntry.getKey();
|
||||
//获取成员变量数据类型
|
||||
Class fieldType = stringFieldEntry.getValue().getType();
|
||||
|
||||
if (fieldType == (String.class)) {
|
||||
contentValues.put(columnName, (String) valueObject);
|
||||
} else if (fieldType == (Integer.class)) {
|
||||
contentValues.put(columnName, (Integer) valueObject);
|
||||
} else if (fieldType == (Long.class)) {
|
||||
contentValues.put(columnName, (Long) valueObject);
|
||||
} else if (fieldType == (Double.class)) {
|
||||
contentValues.put(columnName, (Double) valueObject);
|
||||
} else if (fieldType == (Boolean.class)) {
|
||||
if (((boolean) valueObject)) {
|
||||
contentValues.put(columnName, 1);
|
||||
} else {
|
||||
contentValues.put(columnName, 0);
|
||||
}
|
||||
} else if (fieldType == (byte[].class)) {
|
||||
contentValues.put(columnName, (byte[]) valueObject);
|
||||
} else {
|
||||
//未知类型
|
||||
throw new UnsupportedOperationException("未定义的数据类型:fieldName= " + columnName + " fieldType= " + fieldType);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Logger.d(TAG, "contentValues:" + contentValues);
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询使用的 条件值对象
|
||||
*/
|
||||
private ContentValues getContentValuesForQuery(T entity) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
try {
|
||||
if (entity != null) {
|
||||
Set<Map.Entry<String, Field>> fieldIterator = cacheField.entrySet();
|
||||
for (Map.Entry<String, Field> stringFieldEntry : fieldIterator) {
|
||||
if (stringFieldEntry.getValue().get(entity) != null) {
|
||||
// 针对Boolean类型进行处理
|
||||
if (stringFieldEntry.getValue().get(entity) instanceof Boolean) {
|
||||
if ((boolean) stringFieldEntry.getValue().get(entity)) {
|
||||
contentValues.put(stringFieldEntry.getKey(), "1");
|
||||
} else {
|
||||
contentValues.put(stringFieldEntry.getKey(), "0");
|
||||
}
|
||||
}
|
||||
// 其它数据类型处理
|
||||
else {
|
||||
contentValues.put(stringFieldEntry.getKey(),
|
||||
stringFieldEntry.getValue().get(entity).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessError | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件拼接对象
|
||||
*/
|
||||
static class Condition {
|
||||
/**
|
||||
* 条件key拼接
|
||||
* _id=?&&name=?
|
||||
*/
|
||||
private String whereCause;
|
||||
|
||||
/**
|
||||
* 条件值,与 whereCause 顺序一致
|
||||
*/
|
||||
private String[] whereArgs;
|
||||
|
||||
//根据传入的contentValues转换成查询条件
|
||||
public Condition(ContentValues whereContent) {
|
||||
//记录后面填充到查询语句“?”上的数据参数
|
||||
ArrayList<String> argList = new ArrayList<>();
|
||||
//拼接查询语句
|
||||
StringBuilder whereCaseSb = new StringBuilder();
|
||||
|
||||
/*
|
||||
* 是为了链接下面的查询条件条件,也或者是替换没有查询条件的语句。
|
||||
* 比如:要把检索条件作为一个参数传递给SQL,
|
||||
* 那么,当这个检索语句不存在的话就可以给它赋值为1=1.
|
||||
* 这样就避免了SQL出错,也就可以把加条件的SQL和不加条件的SQL合二为一。
|
||||
*/
|
||||
whereCaseSb.append(" 1=1 ");
|
||||
|
||||
Set<String> keys = whereContent.keySet();
|
||||
|
||||
//因为使用了“1=1”,所以即便是这里没有任何数据拼接,也是可以正常
|
||||
for (String key : keys) {
|
||||
Object valueObject = whereContent.get(key);
|
||||
if (valueObject != null) {
|
||||
String value = (String) valueObject;
|
||||
//拼接查询条件语句
|
||||
//1:1 and _id=? and name=?
|
||||
whereCaseSb.append(" and " + key + " =?");
|
||||
//记录?对应的value
|
||||
argList.add(value);
|
||||
}
|
||||
}
|
||||
//集合转成数组
|
||||
this.whereArgs = argList.toArray(new String[argList.size()]);
|
||||
this.whereCause = whereCaseSb.toString();
|
||||
}
|
||||
|
||||
public String getWhereCause() {
|
||||
return this.whereCause;
|
||||
}
|
||||
|
||||
public String[] getWhereArgs() {
|
||||
return this.whereArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@ import com.mogo.utils.sqlite.proxy.BaseDaoProxyLog
|
||||
* <p>数据库处理工厂</p>
|
||||
* Created by donghongyu on 2019/9/6.
|
||||
*/
|
||||
open class BaseDaoFactory {
|
||||
open class SQLDaoFactory {
|
||||
|
||||
//默认数据库名称
|
||||
private var dbName = "MoGoSQLite.db"
|
||||
|
||||
companion object {
|
||||
//单利工厂
|
||||
private var baseDaoFactory: BaseDaoFactory? = null
|
||||
private var sqlDaoFactory: SQLDaoFactory? = null
|
||||
|
||||
//数据库存储路径
|
||||
private lateinit var sqLiteDatabasePath: String
|
||||
@@ -25,21 +25,21 @@ open class BaseDaoFactory {
|
||||
//数据库操作类
|
||||
private var sqLiteDatabase: SQLiteDatabase? = null
|
||||
|
||||
fun getInstance(): BaseDaoFactory {
|
||||
if (baseDaoFactory == null) {
|
||||
synchronized(BaseDaoFactory::class.java) {
|
||||
if (baseDaoFactory == null) {
|
||||
baseDaoFactory = BaseDaoFactory()
|
||||
fun getInstance(): SQLDaoFactory {
|
||||
if (sqlDaoFactory == null) {
|
||||
synchronized(SQLDaoFactory::class.java) {
|
||||
if (sqlDaoFactory == null) {
|
||||
sqlDaoFactory = SQLDaoFactory()
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseDaoFactory!!
|
||||
return sqlDaoFactory!!
|
||||
}
|
||||
}
|
||||
|
||||
//获取数据库操作对象
|
||||
fun <T : Any> getBaseDao(context: Context, entityClass: Class<T>): IBaseDao<T>? {
|
||||
var baseDao: IBaseDao<T>? = null
|
||||
fun <T : Any> getBaseDao(context: Context, entityClass: Class<T>): SQLIDao<T>? {
|
||||
var baseDao: SQLIDao<T>? = null
|
||||
|
||||
try {
|
||||
//获取数据库名称,如果没有设置则使用默认名称
|
||||
@@ -49,12 +49,14 @@ open class BaseDaoFactory {
|
||||
}
|
||||
//openOrCreateDatabase 如果不存在则先创建再打开数据库,如果存在则直接打开。
|
||||
sqLiteDatabasePath =
|
||||
"${context.getDir("database", Context.MODE_APPEND).path}/$dbName"
|
||||
"${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 = BaseDaoProxyLog().bind(SQLBaseDao<T>()) as IBaseDao<T>
|
||||
// baseDao = BaseDao<T>()
|
||||
baseDao = BaseDaoProxyLog().bind(SQLBaseDao<T>()) as SQLIDao<T>
|
||||
|
||||
baseDao.init(sqLiteDatabase!!, entityClass)
|
||||
} catch (e: Exception) {
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.mogo.utils.sqlite;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库操作接口
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public interface SQLIDao<T> {
|
||||
/**
|
||||
* 初始化数据库连接
|
||||
*/
|
||||
boolean init(SQLiteDatabase sqLiteDatabase, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* 将 [entity] 进行数据插入
|
||||
*/
|
||||
long insert(T entity);
|
||||
|
||||
/**
|
||||
* 根据条件 [where] 进行数据删除,如果[where]==只初始化不赋值 则代表删除所有数据
|
||||
*/
|
||||
int delete(T where);
|
||||
|
||||
/**
|
||||
* 根据条件 [where] 进行数据更新,如果[where]==只初始化不赋值 则代表删除所有数据
|
||||
*/
|
||||
int update(T where, T newEntity);
|
||||
|
||||
/**
|
||||
* @param where 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
|
||||
* @return 结果集合
|
||||
*/
|
||||
List<T> query(T where);
|
||||
|
||||
/**
|
||||
* @param where 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
|
||||
* @param orderBy 排序字段
|
||||
* @return 结果集合
|
||||
*/
|
||||
List<T> query(T where, String orderBy);
|
||||
|
||||
/**
|
||||
* @param where 根据条件 [where] 进行数据查询,如果[where]==只初始化不赋值 则代表查询所有数据
|
||||
* @param orderBy 排序字段
|
||||
* @param isOrderDESC 是否倒序
|
||||
* @return 结果集合
|
||||
*/
|
||||
List<T> query(T where, String orderBy, boolean isOrderDESC);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.mogo.utils.sqlite.proxy
|
||||
|
||||
import android.util.Log
|
||||
import com.mogo.utils.logger.Logger
|
||||
import com.mogo.utils.network.utils.GsonUtil
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
@@ -24,8 +25,8 @@ class BaseDaoProxyLog : InvocationHandler {
|
||||
this.target = target
|
||||
//取得代理对象
|
||||
return Proxy.newProxyInstance(
|
||||
target.javaClass.classLoader,
|
||||
target.javaClass.interfaces, this
|
||||
target.javaClass.classLoader,
|
||||
target.javaClass.interfaces, this
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,11 +41,11 @@ class BaseDaoProxyLog : InvocationHandler {
|
||||
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||
var result: Any? = null
|
||||
//反射方法前调用
|
||||
Log.i("数据库代理", "当前执行>>${method.name}")
|
||||
Logger.i("SQL数据库管理", "当前执行>>${method.name}>>")
|
||||
//反射执行方法 相当于调用target.sayHelllo;
|
||||
result = method.invoke(target, *args)
|
||||
//反射方法后调用.
|
||||
Log.i("数据库代理", "执行结果>>$result")
|
||||
Logger.i("SQL数据库管理", "执行结果>>$result")
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -64,30 +64,35 @@ MAP_CUSTOM_VERSION=1.2.1.9
|
||||
|
||||
## 工程外部模块
|
||||
# 探路
|
||||
MOGO_MODULE_TANLU_VERSION=1.3.1.20
|
||||
MOGO_MODULE_TANLU_VERSION=1.3.1.24
|
||||
# 车聊聊
|
||||
CARCHATTING_VERSION=1.4.8
|
||||
CARCHATTING_VERSION=1.5.1
|
||||
# 车聊聊接口
|
||||
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
|
||||
# 推送
|
||||
MOGO_MODULE_PUSH_VERSION=1.1.6.1
|
||||
MOGO_MODULE_PUSH_VERSION=1.1.6.2
|
||||
MOGO_MODULE_PUSH_BASE_VERSION=1.1.5.5
|
||||
MOGO_MODULE_PUSH_NOOP_VERSION=1.1.5.6
|
||||
# 广告资源位
|
||||
MOGO_MODULE_AD_CARD_VERSION=1.0.1
|
||||
# 探路上报和分享模块
|
||||
TANLULIB_VERSION=1.3.1.20
|
||||
TANLULIB_VERSION=1.3.1.24
|
||||
MOGO_TANLU_API_VERSION = 1.0.0-SNAPSHOT
|
||||
|
||||
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
|
||||
# 小控件
|
||||
MOGO_MODULE_WIDGETS_VERSION = 1.2.1.10-SNAPSHOT
|
||||
|
||||
# Boost分包
|
||||
BOOST_MULTIDEX_VERSION=1.0.0
|
||||
@@ -102,7 +107,9 @@ MOGO_MODULE_SPLASH_VERSION = 1.0.0-SNAPSHOT
|
||||
MOGO_MODULE_SPLASH_NOOP_VERSION = 1.0.0-SNAPSHOT
|
||||
|
||||
# loglib
|
||||
LOGLIB_VERSION = 1.0.0-SNAPSHOT
|
||||
LOGLIB_VERSION = 1.0.4
|
||||
# monitor
|
||||
MOGO_MODULE_MONITOR_VERSION = 1.0.0-SNAPSHOT
|
||||
|
||||
## 产品库必备配置,产品库自动对versionCode和versionName版本进行升级
|
||||
applicationId=com.mogo.launcer
|
||||
|
||||
@@ -522,6 +522,9 @@ public class AMapNaviViewWrapper implements IMogoMapView,
|
||||
}
|
||||
if ( checkAMapView() ) {
|
||||
MyLocationStyle style = mMapView.getMap().getMyLocationStyle();
|
||||
if ( style == null ) {
|
||||
style = new MyLocationStyle();
|
||||
}
|
||||
style.showMyLocation( visible );
|
||||
if ( visible ) {
|
||||
// 强制刷新一遍车标
|
||||
@@ -541,6 +544,9 @@ public class AMapNaviViewWrapper implements IMogoMapView,
|
||||
}
|
||||
if ( checkAMapView() ) {
|
||||
MyLocationStyle style = mMapView.getMap().getMyLocationStyle();
|
||||
if ( style == null ) {
|
||||
style = new MyLocationStyle();
|
||||
}
|
||||
style.showMyLocation( true );
|
||||
style.myLocationIcon( BitmapDescriptorFactory.fromView( view ) );
|
||||
mMapView.getMap().setMyLocationStyle( style );
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface IMogoMarkerClickListener {
|
||||
* 事件是否继续往下传递
|
||||
*
|
||||
* @param marker
|
||||
* @return true - 时间已经处理完毕不继续往下传,否则继续往下传
|
||||
* @return true - 事件已经处理完毕不继续往下传,否则继续往下传
|
||||
*/
|
||||
boolean onMarkerClicked( IMogoMarker marker );
|
||||
}
|
||||
|
||||
@@ -75,7 +75,10 @@ class MogoMapDelegateFactory {
|
||||
}
|
||||
|
||||
public static IMogoNavi getNaviDelegate( Context context ) {
|
||||
if ( AppUtils.isAppInstalled( context, "com.autonavi.amapauto" ) ) {
|
||||
|
||||
if ( DebugConfig.isUseCustomNavi() ) {
|
||||
return NaviClient.getInstance( context );
|
||||
} else if ( AppUtils.isAppInstalled( context, "com.autonavi.amapauto" ) ) {
|
||||
return AutoNaviClient.getInstance( context );
|
||||
} else {
|
||||
if ( DebugConfig.isUseCustomMap() ) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.pm.PackageManager;
|
||||
import android.graphics.Rect;
|
||||
import android.location.Location;
|
||||
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.map.impl.amap.navi.NaviClient;
|
||||
import com.mogo.map.impl.automap.navi.AutoNaviClient;
|
||||
import com.mogo.map.navi.IMogoCarLocationChangedListener2;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.alibaba.arouter'
|
||||
|
||||
android {
|
||||
@@ -39,16 +36,16 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation rootProject.ext.dependencies.androidxccorektx
|
||||
implementation rootProject.ext.dependencies.kotlinstdlibjdk7
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
kapt rootProject.ext.dependencies.aroutercompiler
|
||||
annotationProcessor rootProject.ext.dependencies.aroutercompiler
|
||||
|
||||
if (Boolean.valueOf(RELEASE)) {
|
||||
compileOnly rootProject.ext.dependencies.modulecommon
|
||||
implementation rootProject.ext.dependencies.tanluupload
|
||||
} else {
|
||||
compileOnly project(':modules:mogo-module-common')
|
||||
implementation project(':libraries:tanlulib')
|
||||
}
|
||||
}
|
||||
|
||||
0
libraries/mogo-tanlu-api/consumer-rules.pro
Normal file
0
libraries/mogo-tanlu-api/consumer-rules.pro
Normal file
@@ -1,3 +1,3 @@
|
||||
GROUP=com.mogo.module
|
||||
POM_ARTIFACT_ID=module-event-panel
|
||||
POM_ARTIFACT_ID=module-tanlu-api
|
||||
VERSION_CODE=1
|
||||
@@ -18,6 +18,4 @@
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keep class com.zhidao.mogo.module.event.panel.EventPanelConstants
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.mogo.base.services.apk;
|
||||
package com.zhidao.mogo.tanlu.api;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@@ -15,12 +15,12 @@ import static org.junit.Assert.*;
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith( AndroidJUnit4.class )
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals( "com.mogo.base.services.apk.test", appContext.getPackageName() );
|
||||
assertEquals("com.zhidao.mogo.tanlu.api.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.zhidao.mogo.module.event.panel">
|
||||
package="com.zhidao.mogo.tanlu.api">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.zhidao.mogo.tanlu.api;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.commons.analytics.AnalyticsUtils;
|
||||
import com.mogo.service.IMogoServiceApis;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.service.tanlu.IMogoTanluProvider;
|
||||
import com.mogo.service.tanlu.TanluUploadParams;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.zhidao.roadcondition.service.MainService;
|
||||
import com.zhidao.roadcondition.service.UploadParams;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zhidao.mogo.tanlu.api.TanluApiConst.MODULE_NAME;
|
||||
import static com.zhidao.mogo.tanlu.api.TanluApiConst.MODULE_PATH;
|
||||
|
||||
/**
|
||||
* 探路api
|
||||
*
|
||||
* @author tongchenfei
|
||||
*/
|
||||
@Route(path = MODULE_PATH)
|
||||
public class MogoTanluApiProvider implements IMogoTanluProvider {
|
||||
private Context context;
|
||||
|
||||
/**
|
||||
* 上传情报
|
||||
*
|
||||
* @param params 情报类型
|
||||
*/
|
||||
@Override
|
||||
public void uploadRoadCondition(TanluUploadParams params) {
|
||||
if(params!=null) {
|
||||
Logger.d(MODULE_NAME, "uploadRoadCondition: " + params);
|
||||
Map<String, Object> properties = new ArrayMap<>();
|
||||
properties.put("type", params.getEventType());
|
||||
properties.put("from", params.getFromType());
|
||||
AnalyticsUtils.track("v2x_share_type", properties);
|
||||
MainService.Companion.launchService(context, new UploadParams(params.getEventType(),
|
||||
params.getFromType(), params.getDuration()));
|
||||
}else{
|
||||
throw new IllegalArgumentException("TanluUploadParams 不允许为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启探路业务服务
|
||||
*/
|
||||
@Override
|
||||
public void startTanluService() {
|
||||
Logger.d(MODULE_NAME, "startTanluService");
|
||||
MainService.Companion.launchService(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.zhidao.mogo.tanlu.api;
|
||||
|
||||
/**
|
||||
* 探路api相关常量
|
||||
* @author tongchenfei
|
||||
*/
|
||||
public class TanluApiConst {
|
||||
public static final String MODULE_NAME = "MogoTanluApi";
|
||||
public static final String MODULE_PATH = "/tanlulib/api";
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.mogo.base.services.apk;
|
||||
package com.zhidao.mogo.tanlu.api;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -12,6 +12,6 @@ import static org.junit.Assert.*;
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals( 4, 2 + 2 );
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
1
libraries/tanlulib/.gitignore
vendored
Normal file
1
libraries/tanlulib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
70
libraries/tanlulib/build.gradle
Normal file
70
libraries/tanlulib/build.gradle
Normal file
@@ -0,0 +1,70 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'android-aspectjx'
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'com.zhidaoauto.common:service:1.0.4.10'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
||||
implementation 'com.zhidaoauto.controller:api:1.0.8'
|
||||
implementation 'com.zhidao.cosupload:cosuploadsdk:1.1.6'
|
||||
implementation 'com.zhidao.video:video-processor:1.0.2.1'
|
||||
implementation 'com.foundation.utils:common-utils:1.0.7'
|
||||
|
||||
compileOnly rootProject.ext.dependencies.mogocommons
|
||||
implementation rootProject.ext.dependencies.eventbus
|
||||
implementation rootProject.ext.dependencies.coroutinescore
|
||||
implementation rootProject.ext.dependencies.coroutinesandroid
|
||||
implementation rootProject.ext.dependencies.retrofit
|
||||
implementation rootProject.ext.dependencies.retrofitconvertergson
|
||||
implementation rootProject.ext.dependencies.gson
|
||||
implementation rootProject.ext.dependencies.rxjava
|
||||
implementation rootProject.ext.dependencies.rxandroid
|
||||
compileOnly rootProject.ext.dependencies.mogomap
|
||||
implementation rootProject.ext.dependencies.aspectj
|
||||
implementation rootProject.ext.dependencies.analytics
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
4
libraries/tanlulib/consumer-rules.pro
Normal file
4
libraries/tanlulib/consumer-rules.pro
Normal file
@@ -0,0 +1,4 @@
|
||||
-keep class com.zhidao.roadcondition.model.**{*;}
|
||||
-keep class com.zhidao.roadcondition.service.*{*;}
|
||||
-keep class com.zhidao.roadcondition.ShareRoadReceiver.*{*;}
|
||||
|
||||
3
libraries/tanlulib/gradle.properties
Normal file
3
libraries/tanlulib/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
GROUP=com.mogo.module
|
||||
POM_ARTIFACT_ID=module-tanlu-upload
|
||||
VERSION_CODE=1
|
||||
@@ -19,9 +19,9 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-keep class com.zhidao.roadcondition.model.**{*;}
|
||||
-keep class com.zhidao.roadcondition.service.*{*;}
|
||||
-keep class com.zhidao.roadcondition.ShareRoadReceiver.*{*;}
|
||||
|
||||
|
||||
|
||||
#-----EventPanel------
|
||||
-keep class com.zhidao.mogo.module.event.panel.bean.** {*;}
|
||||
-keep class com.zhidao.mogo.module.event.panel.dao.** {*;}
|
||||
-keep class com.zhidao.mogo.module.event.panel.listener.** {*;}
|
||||
-keep class com.zhidao.mogo.module.event.panel.EventPanelConstants
|
||||
25
libraries/tanlulib/src/main/AndroidManifest.xml
Normal file
25
libraries/tanlulib/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.zhidao.roadcondition">
|
||||
|
||||
<application>
|
||||
<!--分享相关广播-->
|
||||
<receiver
|
||||
android:name=".receiver.ShareRoadReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.zhidao.share.roadcondition.action" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!--获取图片和视频的服务-->
|
||||
<service
|
||||
android:name=".service.MainService"
|
||||
android:enabled="true" />
|
||||
|
||||
<service
|
||||
android:name=".service.DelayService"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.zhidao.roadcondition.aspect
|
||||
|
||||
import android.util.Log
|
||||
import com.zhidao.roadcondition.util.CarNet_Alive
|
||||
import com.zhidao.roadcondition.util.trackNormalEvent
|
||||
import org.aspectj.lang.annotation.*
|
||||
|
||||
@Aspect
|
||||
class DAUAspectj {
|
||||
|
||||
companion object {
|
||||
const val TAG = "DAUAspectj"
|
||||
}
|
||||
|
||||
@Pointcut("execution(* com.zhidao.roadcondition.splash_module.SplashActivity.initView())")
|
||||
fun callDAU() {
|
||||
}
|
||||
|
||||
@Pointcut("execution(* com.zhidao.roadcondition.service.RoadInfoService.launchMainActivity(..))")
|
||||
fun callDAUOther(){
|
||||
|
||||
}
|
||||
|
||||
@Before("callDAU() || callDAUOther()")
|
||||
fun trackDAU() {
|
||||
Log.i(TAG, "trackDAU")
|
||||
trackNormalEvent(CarNet_Alive, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zhidao.roadcondition.aspect;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Target({TYPE, METHOD, CONSTRUCTOR})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DebugLog {
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.zhidao.roadcondition.aspect
|
||||
|
||||
import android.os.Looper
|
||||
import android.os.Trace
|
||||
import android.util.Log
|
||||
import com.zhidao.roadcondition.BuildConfig
|
||||
import org.aspectj.lang.ProceedingJoinPoint
|
||||
import org.aspectj.lang.annotation.Around
|
||||
import org.aspectj.lang.annotation.Aspect
|
||||
import org.aspectj.lang.annotation.Pointcut
|
||||
import org.aspectj.lang.reflect.CodeSignature
|
||||
import org.aspectj.lang.reflect.MethodSignature
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Aspect
|
||||
class LogAspectj {
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var enable: Boolean = BuildConfig.DEBUG
|
||||
}
|
||||
|
||||
@Pointcut("within(@com.zhidao.roadcondition.aspect.DebugLog *)")
|
||||
fun withinAnnotatedClass() {}
|
||||
|
||||
@Pointcut("execution(!synthetic * *(..))&& withinAnnotatedClass()")
|
||||
fun methodInsideAnnotatedType() {}
|
||||
|
||||
@Pointcut("execution(!synthetic *.new(..))&& withinAnnotatedClass()")
|
||||
fun constructorInsideAnnotatedType() {}
|
||||
|
||||
@Pointcut("execution(@com.zhidao.roadcondition.aspect.DebugLog * *(..))|| methodInsideAnnotatedType()")
|
||||
fun method() {}
|
||||
|
||||
@Pointcut("execution(@com.zhidao.roadcondition.aspect.DebugLog *.new(..))|| constructorInsideAnnotatedType()")
|
||||
fun constructor() {}
|
||||
|
||||
@Around("method() || constructor()")
|
||||
fun logExecute(joinPoint: ProceedingJoinPoint) {
|
||||
|
||||
enterMethod(joinPoint)
|
||||
|
||||
var startNanos = System.nanoTime()
|
||||
var result = joinPoint.proceed()
|
||||
var stopNanos = System.nanoTime()
|
||||
var lengthMill = TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos)
|
||||
|
||||
exitMethod(joinPoint, result as Any?, lengthMill)
|
||||
}
|
||||
|
||||
private fun enterMethod(joinPoint: ProceedingJoinPoint) {
|
||||
if (!enable) return
|
||||
|
||||
val signature = joinPoint.signature as CodeSignature
|
||||
val cls = signature.declaringType
|
||||
val methodName = signature.name
|
||||
val parameterNames = signature.parameterNames
|
||||
val parameterValues = joinPoint.args
|
||||
|
||||
var builder = StringBuilder("\u21E2 ")
|
||||
builder.append(methodName).append('(')
|
||||
parameterValues.forEachIndexed { index, any ->
|
||||
if (index > 0) {
|
||||
builder.append(",")
|
||||
}
|
||||
builder.append(parameterNames[index]).append('=')
|
||||
builder.append(parameterValues[index])
|
||||
}
|
||||
builder.append(')')
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
builder.append("[Thread:\"").append(Thread.currentThread().name).append("\"]")
|
||||
}
|
||||
Log.i(asTag(cls), builder.toString())
|
||||
|
||||
val section = builder.toString().substring(2)
|
||||
Trace.beginSection(section)
|
||||
}
|
||||
|
||||
private fun exitMethod(joinPoint: ProceedingJoinPoint, result: Any?, lengthMill: Long) {
|
||||
if (!enable) return
|
||||
|
||||
Trace.endSection()
|
||||
|
||||
val signature = joinPoint.signature
|
||||
val cls = signature.declaringType
|
||||
val methodName = signature.name
|
||||
var hasReturnType = signature is MethodSignature
|
||||
&& signature.returnType != Void.TYPE
|
||||
|
||||
var builder = StringBuilder("\u21E0 ")
|
||||
.append(methodName)
|
||||
.append("[")
|
||||
.append(lengthMill)
|
||||
.append("ms]")
|
||||
|
||||
if (hasReturnType) {
|
||||
builder.append(" = ")
|
||||
builder.append(result.let {
|
||||
result.toString()
|
||||
})
|
||||
}
|
||||
Log.i(asTag(cls), builder.toString())
|
||||
}
|
||||
|
||||
private fun asTag(cls: Class<*>): String {
|
||||
// if (cls.isAnonymousClass) {
|
||||
// return asTag(cls.enclosingClass)
|
||||
// }
|
||||
return cls.simpleName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.zhidao.roadcondition.base
|
||||
|
||||
import android.app.IntentService
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
|
||||
|
||||
open class BaseIntentService : IntentService("BaseIntentService") {
|
||||
|
||||
protected var tag: String = this.javaClass.simpleName
|
||||
|
||||
override fun onHandleIntent(p0: Intent?) {
|
||||
tag = this.javaClass.simpleName
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
override fun onStart(intent: Intent?, startId: Int) {
|
||||
super.onStart(intent, startId)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return super.onBind(intent)
|
||||
}
|
||||
|
||||
override fun setIntentRedelivery(enabled: Boolean) {
|
||||
super.setIntentRedelivery(enabled)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.zhidao.roadcondition.base
|
||||
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
|
||||
open class BaseRepository {
|
||||
|
||||
suspend fun <T : Any> apiCall(call: suspend () -> BaseResponse<T>): BaseResponse<T> {
|
||||
return call.invoke()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.zhidao.roadcondition.constant
|
||||
|
||||
public val STRATEGY_TYPE_PHOTO: String = "0FOoOuB7" //拍照的策略ID
|
||||
public val STRATEGY_TYPE_VIDEO: String = "gVCl9VdW" //拍视频的策略ID
|
||||
public val SOCKET_MSG_TYPE: Int = 0x040001 //长连接消息类型
|
||||
public val SOCKET_PRODUCT_LINE: Int = 0x04 //长连接消息产品线id,目前SDK是写死的
|
||||
|
||||
const val INFORMATION_DATA_SIZE_LIMIT = 50
|
||||
const val INFORMATION_DEFAULT_MAP_RADIUS = 10
|
||||
|
||||
const val REQUESTCODE_MAINACTIVITY = 0
|
||||
const val REQUESTCODE_MEDIAACTIVITY = 1
|
||||
const val CUSTOM_SEND_CMD = "custom_send_cmd" //主动上报语音命令
|
||||
const val VOICE_PREVIOUS_INFO_CMD = "voice_previous_info_cmd" //上一条
|
||||
const val VOICE_NEXT_INFO_CMD = "voice_next_info_cmd" //下一条
|
||||
|
||||
const val SCHEME_SPLASH_TYPE = "channelType"
|
||||
const val SCHEME_MAIN_TYPE = "type"
|
||||
const val PARAM_MAIN_PAGE_ACTION = "action" // 判断主页该干什么
|
||||
|
||||
const val VAL_ACTION_TQZ = "tqz" //通勤族
|
||||
const val VAL_ACTION_PLAY_DIRECTLY = "play" //直接播放情报
|
||||
const val VAL_ACTION_DHLX = "dhlx" //导航路线
|
||||
|
||||
const val CONFIG_NEED_AUTH = "0001" //公共配置 是否查询授权
|
||||
const val CONFIG_ACTIVE_POSITION = "0002" //公共配置 查询运营位配置
|
||||
|
||||
//广播action、key
|
||||
const val AUTONAVI_STANDARD_BROADCAST_SEND = "AUTONAVI_STANDARD_BROADCAST_SEND"
|
||||
const val AUTONAVI_STANDARD_BROADCAST_ROAD_INFO = "EXTRA_ROAD_INFO"
|
||||
const val AUTONAVI_STANDARD_BROADCAST_EXTRA_STATE = "EXTRA_STATE"
|
||||
//EXTRA_STATE
|
||||
const val AUTO_NAVI_START = 8 //开始导航
|
||||
const val AUTO_NAVI_END = 9 //结束导航
|
||||
|
||||
const val VALUE_DICT_DATA_TYPE = "deva_infomation_type" // dict 数据请求类型:情报类型数据
|
||||
|
||||
//事件类型
|
||||
const val TANLU_TRAFFIC_CHECK = "10002" //交通检查
|
||||
const val TANLU_ROAD_CLOSURE = "10003" //封路
|
||||
const val TANLU_ROAD_WORK = "10006" //施工
|
||||
const val TANLU_ROAD_CONGESTION = "10007" //拥堵
|
||||
const val TANLU_ROAD_PONDING = "10008" //积水
|
||||
const val TANLU_ROAD_HEAVY_FOG = "10010" //大雾
|
||||
const val TANLU_ROAD_ICING = "10011" //积冰
|
||||
const val TANLU_ROAD_ACCIDENT = "10013" //事故
|
||||
const val TANLU_ROAD_CURRENT = "10015" //实时路况
|
||||
|
||||
// 上报类型
|
||||
/**
|
||||
* 用户手点上报
|
||||
*/
|
||||
const val UPLOAD_FROM_USER = "1"
|
||||
/**
|
||||
* 用户语音上报
|
||||
*/
|
||||
const val UPLOAD_FROM_VOICE = "2"
|
||||
/**
|
||||
* 数据策略:拥堵自动上报
|
||||
*/
|
||||
const val UPLOAD_FROM_STRATEGY_BLOCK_AUTO = "3"
|
||||
/**
|
||||
* 数据策略:已有事件云端校验
|
||||
*/
|
||||
const val UPLOAD_FROM_STRATEGY_CLOUD_CHECK = "4"
|
||||
/**
|
||||
* 数据策略:交通事故上报
|
||||
*/
|
||||
const val UPLOAD_FROM_STRATEGY_ACCIDENT_AUTO = "5"
|
||||
|
||||
/**
|
||||
* 默认视频抓取时长,单位是秒
|
||||
*/
|
||||
const val DEFAULT_VIDEO_DURATION = 10
|
||||
|
||||
const val DEF_NEWS_LABEL = "拥堵"
|
||||
const val DEF_NEWS_VALUE = "traffic_jam"
|
||||
const val DEF_NEWS_TYPE = "0"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zhidao.roadcondition.constant
|
||||
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.zhidao.roadcondition.BuildConfig
|
||||
|
||||
class HttpConstants {
|
||||
|
||||
companion object {
|
||||
|
||||
const val DEV_BASE_URL_OWNER = "http://dzt-test.zhidaohulian.com/"
|
||||
const val RELEASE_BASE_URL_OWNER = "http://dzt.zhidaohulian.com/"
|
||||
const val SHOW_BASE_URL_OWNER = "http://dzt-show.zhidaohulian.com/"
|
||||
|
||||
fun getBaseUrl(): String {
|
||||
return when (DebugConfig.getNetMode()) {
|
||||
DebugConfig.NET_MODE_QA -> DEV_BASE_URL_OWNER
|
||||
DebugConfig.NET_MODE_RELEASE -> RELEASE_BASE_URL_OWNER
|
||||
DebugConfig.NET_MODE_DEMO -> SHOW_BASE_URL_OWNER
|
||||
else -> DEV_BASE_URL_OWNER
|
||||
}
|
||||
}
|
||||
|
||||
// fun getBaseUrl1(): String {
|
||||
// return when (BuildConfig.BUILD_TYPE) {
|
||||
// "debug" -> DEV_BASE_URL_OWNER
|
||||
// "qa" -> DEV_BASE_URL_OWNER
|
||||
// "release" -> RELEASE_BASE_URL_OWNER
|
||||
// "show" -> SHOW_BASE_URL_OWNER
|
||||
// else -> RELEASE_BASE_URL_OWNER
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zhidao.roadcondition.event
|
||||
|
||||
|
||||
/**
|
||||
* @description
|
||||
*
|
||||
* @author lixiaopeng
|
||||
* @since 2019-10-13
|
||||
*/
|
||||
class GetImageSuccessEvent {
|
||||
private var imageUrl: String? = null
|
||||
private var type: String? = null
|
||||
|
||||
constructor(imageUrl: String?, type: String?) {
|
||||
this.imageUrl = imageUrl
|
||||
this.type = type
|
||||
}
|
||||
|
||||
fun getImageUrl(): String? {
|
||||
return imageUrl
|
||||
}
|
||||
|
||||
fun getType(): String? {
|
||||
return type
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.zhidao.roadcondition.event
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class LatLngStickyEventBus {
|
||||
|
||||
companion object {
|
||||
private var mEventBus = EventBus.builder()
|
||||
.logNoSubscriberMessages(false)
|
||||
.sendNoSubscriberEvent(false)
|
||||
.build()
|
||||
|
||||
fun getInstance(): EventBus {
|
||||
return mEventBus
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zhidao.roadcondition.exception
|
||||
|
||||
|
||||
class ApiException : Exception {
|
||||
|
||||
companion object{
|
||||
val NETWORK_API_EXCEPTION = ApiException(1, "network is error")
|
||||
val NULL_REQUEST_DATA_API_EXCEPTION = ApiException(2, "request data is null")
|
||||
}
|
||||
|
||||
private var code: Int = 0
|
||||
private var msg: String = ""
|
||||
|
||||
constructor(code: Int, msg: String) : super(msg) {
|
||||
this.code = code
|
||||
this.msg = msg
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
class BaseRequest<T>(var sn: String, var data: T?) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import com.zhidao.roadcondition.constant.HttpConstants
|
||||
|
||||
class BaseResponse<out T>(val code: Int, val msg: String, val result: T) {
|
||||
fun isSuccess(baseUrl: String): Boolean {
|
||||
return when (baseUrl) {
|
||||
HttpConstants.getBaseUrl() -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
class CityStrategy {
|
||||
|
||||
var video: Video
|
||||
var pic: Pic
|
||||
|
||||
constructor(video: Video, pic: Pic) {
|
||||
this.video = video
|
||||
this.pic = pic
|
||||
}
|
||||
}
|
||||
|
||||
fun Video.getMaxSpeed(): Int {
|
||||
return if (maxSpeed == 0) {
|
||||
-1
|
||||
} else {
|
||||
maxSpeed
|
||||
}
|
||||
}
|
||||
|
||||
class Video {
|
||||
var strategyId: String //策略ID
|
||||
var reportType: Int //一次性、周期性
|
||||
var reportTimeInterval: Int //上传时间间隔 单位:分钟
|
||||
var infoTimeout: Int //情报失效时间 单位:分钟
|
||||
var minSpeed: Int = -1//最小速度
|
||||
var maxSpeed: Int = -1//最大速度
|
||||
var strategyType: Int //策略类型:城市、热门区域、非上报区域等
|
||||
|
||||
constructor(
|
||||
strategyId: String,
|
||||
reportType: Int,
|
||||
reportTimeInterval: Int,
|
||||
infoTimeout: Int,
|
||||
minSpeed: Int,
|
||||
maxSpeed: Int,
|
||||
strategyType: Int
|
||||
) {
|
||||
this.strategyId = strategyId
|
||||
this.reportType = reportType
|
||||
this.reportTimeInterval = reportTimeInterval
|
||||
this.infoTimeout = infoTimeout
|
||||
this.minSpeed = minSpeed
|
||||
this.maxSpeed = maxSpeed
|
||||
this.strategyType = strategyType
|
||||
}
|
||||
}
|
||||
|
||||
fun Pic.getMaxSpeed(): Int {
|
||||
return if (maxSpeed == 0) {
|
||||
-1
|
||||
} else {
|
||||
maxSpeed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Pic {
|
||||
var strategyId: String //策略ID
|
||||
var reportType: Int //一次性、周期性
|
||||
var reportTimeInterval: Int //上传时间间隔 单位:分钟
|
||||
var infoTimeout: Int //情报失效时间 单位:分钟
|
||||
var minSpeed: Int = -1 //最小速度
|
||||
var maxSpeed: Int = -1 //最大速度
|
||||
var strategyType: Int //策略类型:城市、热门区域、非上报区域等
|
||||
|
||||
constructor(
|
||||
strategyId: String,
|
||||
reportType: Int,
|
||||
reportTimeInterval: Int,
|
||||
infoTimeout: Int,
|
||||
minSpeed: Int,
|
||||
maxSpeed: Int,
|
||||
strategyType: Int
|
||||
) {
|
||||
this.strategyId = strategyId
|
||||
this.reportType = reportType
|
||||
this.reportTimeInterval = reportTimeInterval
|
||||
this.infoTimeout = infoTimeout
|
||||
this.minSpeed = minSpeed
|
||||
this.maxSpeed = maxSpeed
|
||||
this.strategyType = strategyType
|
||||
}
|
||||
}
|
||||
|
||||
class StrategyRequest {
|
||||
var lon: Double
|
||||
var lat: Double
|
||||
var cityCode: String
|
||||
|
||||
constructor(lon: Double, lat: Double, cityCode: String) {
|
||||
this.lon = lon
|
||||
this.lat = lat
|
||||
this.cityCode = cityCode
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
|
||||
fun CommonConfig.isActiveNonNull():Boolean{
|
||||
return active!=null
|
||||
}
|
||||
|
||||
//fun CommonConfig.isPromotionNonNull():Boolean{
|
||||
// return promotion!=null
|
||||
//}
|
||||
|
||||
class CommonConfig {
|
||||
|
||||
var active:Active //活动配置
|
||||
// var promotion:Promotion //Splash页面图片以及语音推广配置
|
||||
var auth:Auth //授权配置
|
||||
|
||||
constructor(active: Active, auth: Auth) {
|
||||
this.active = active
|
||||
// this.promotion = promotion
|
||||
this.auth = auth
|
||||
}
|
||||
}
|
||||
|
||||
class Active{
|
||||
var imageUrl:String
|
||||
var webUrl:String
|
||||
var status:Int
|
||||
|
||||
constructor(imageUrl: String, webUrl: String, status: Int) {
|
||||
this.imageUrl = imageUrl
|
||||
this.webUrl = webUrl
|
||||
this.status = status
|
||||
}
|
||||
}
|
||||
|
||||
class Promotion{
|
||||
var imageUrl:String
|
||||
var voiceContent:String
|
||||
var status:Int
|
||||
|
||||
constructor(imageUrl: String, voiceContent: String, status: Int) {
|
||||
this.imageUrl = imageUrl
|
||||
this.voiceContent = voiceContent
|
||||
this.status = status
|
||||
}
|
||||
}
|
||||
|
||||
class Auth{
|
||||
var isNeedAuth:Int
|
||||
|
||||
constructor(isNeedAuth: Int) {
|
||||
this.isNeedAuth = isNeedAuth
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
data class InformationBody(
|
||||
val data: String,
|
||||
val addr: String,
|
||||
val areaCode: String,
|
||||
val areaName: String,
|
||||
val cityCode: String,
|
||||
val cityName: String,
|
||||
val generateTime: Long,
|
||||
val lat: Double,
|
||||
val lon: Double,
|
||||
val provinceName: String,
|
||||
val sn: String,
|
||||
val street: String,
|
||||
val type: Int,
|
||||
val uid: Int,
|
||||
val infoType: Int,
|
||||
val infoTimeout:Int,
|
||||
val trafficInfoType:String, // 上报情报类型
|
||||
val isShare: Boolean, // 是否分享给附近车机
|
||||
val direction: Float,
|
||||
val poiType: String, //类型分类
|
||||
val mainInfoId: Long //事件id
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-22
|
||||
*
|
||||
* 一次情报的数据
|
||||
*/
|
||||
class InformationResource {
|
||||
|
||||
var id: Long
|
||||
var isCosResourceReady: Boolean = false
|
||||
var isInformationSelected: Boolean = false
|
||||
|
||||
var sourceType: Int = 0 // 情报载体类型:图片、视频
|
||||
var cosParameter: Map<String, String>? = null // 情报参数
|
||||
var informationType: InformationType? = null //情报类型
|
||||
var isCustomSend: Boolean = false // 自动上传
|
||||
|
||||
var callback: ((customSend: Boolean) -> Unit)? = null
|
||||
|
||||
lateinit var newsType: String // 埋点:情报类型
|
||||
lateinit var operType: String // 埋点:操作类型
|
||||
|
||||
constructor(id: Long) {
|
||||
this.id = id
|
||||
}
|
||||
|
||||
fun isReady() = isCosResourceReady and isInformationSelected
|
||||
|
||||
fun release() {
|
||||
cosParameter = null
|
||||
informationType = null
|
||||
callback = null
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "upload information: sourceType=${sourceType}, informationType={${informationType?.dictLabel}, ${informationType?.dictValue}}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.zhidao.roadcondition.constant.DEF_NEWS_LABEL
|
||||
import com.zhidao.roadcondition.constant.DEF_NEWS_TYPE
|
||||
import com.zhidao.roadcondition.constant.DEF_NEWS_VALUE
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-18
|
||||
*
|
||||
* 情报类型
|
||||
*/
|
||||
data class InformationType(var dictLabel: String, var dictValue: String, var remark: String) {
|
||||
companion object {
|
||||
val def = InformationType(DEF_NEWS_LABEL, DEF_NEWS_VALUE, DEF_NEWS_TYPE)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
when (other) {
|
||||
is InformationType -> return other.dictValue.compareTo(dictValue) == 0
|
||||
}
|
||||
return super.equals(other)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return Gson().toJson(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-18
|
||||
*
|
||||
* 描述
|
||||
*/
|
||||
data class InformationTypeResult(var types: List<InformationType>)
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.amap.api.maps.model.LatLng
|
||||
|
||||
|
||||
fun Informations.toLatLng(): LatLng {
|
||||
return LatLng(lat, lon)
|
||||
}
|
||||
|
||||
class Informations(
|
||||
var type: Int,
|
||||
var lon: Double,
|
||||
var lat: Double,
|
||||
var addr: String?,
|
||||
var generateTime: Long,
|
||||
var cityName: String?,
|
||||
// var items: ArrayList<Items>,
|
||||
var distance: Int,
|
||||
var nickName: String?,
|
||||
var headImgUrl: String?
|
||||
) :
|
||||
Parcelable {
|
||||
|
||||
var position = 0
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readInt(),
|
||||
parcel.readDouble(),
|
||||
parcel.readDouble(),
|
||||
parcel.readString(),
|
||||
parcel.readLong(),
|
||||
parcel.readString(),
|
||||
// parcel.readArrayList(Items::class.java.classLoader) as ArrayList<Items>,
|
||||
parcel.readInt(),
|
||||
parcel.readString(),
|
||||
parcel.readString()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(type)
|
||||
parcel.writeDouble(lon)
|
||||
parcel.writeDouble(lat)
|
||||
parcel.writeString(addr)
|
||||
parcel.writeLong(generateTime)
|
||||
parcel.writeString(cityName)
|
||||
// parcel.writeList(items)
|
||||
parcel.writeInt(distance)
|
||||
parcel.writeString(nickName)
|
||||
parcel.writeString(headImgUrl)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Informations> {
|
||||
override fun createFromParcel(parcel: Parcel): Informations {
|
||||
return Informations(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Informations?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class Items(var url: String?, var thumbnail: String? = null) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readString(),
|
||||
parcel.readString()
|
||||
) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(url)
|
||||
parcel.writeString(thumbnail)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Items> {
|
||||
override fun createFromParcel(parcel: Parcel): Items {
|
||||
return Items(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Items?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.amap.api.services.core.LatLonPoint
|
||||
|
||||
|
||||
fun LocationInfo.toLatLng(): LatLng {
|
||||
return LatLng(latitude,longitude)
|
||||
}
|
||||
|
||||
fun LocationInfo.toLatLngPoint():LatLonPoint{
|
||||
return LatLonPoint(latitude,longitude)
|
||||
}
|
||||
|
||||
class LocationInfo {
|
||||
var provinceName: String = "" //省的名称
|
||||
var cityName: String = "" //城市的名称
|
||||
var cityCode :String = "" //城市编码
|
||||
var areaName :String = "" //区县名称
|
||||
var areaCode :String = "" //区县编码
|
||||
var street :String = "" //街道名称
|
||||
var longitude: Double = 0.0
|
||||
var latitude: Double = 0.0
|
||||
var address: String = ""
|
||||
var time: Long = 0L
|
||||
var direction: Float = 0.0f
|
||||
constructor()
|
||||
|
||||
constructor(longitude: Double, latitude: Double, address: String, time: Long) {
|
||||
this.longitude = longitude
|
||||
this.latitude = latitude
|
||||
this.address = address
|
||||
this.time = time
|
||||
}
|
||||
|
||||
constructor(
|
||||
provinceName: String,
|
||||
cityName: String,
|
||||
cityCode: String,
|
||||
areaName: String,
|
||||
areaCode: String,
|
||||
street: String,
|
||||
longitude: Double,
|
||||
latitude: Double,
|
||||
address: String,
|
||||
time: Long,
|
||||
direction: Float = 0.0f
|
||||
) {
|
||||
this.provinceName = provinceName
|
||||
this.cityName = cityName
|
||||
this.cityCode = cityCode
|
||||
this.areaName = areaName
|
||||
this.areaCode = areaCode
|
||||
this.street = street
|
||||
this.longitude = longitude
|
||||
this.latitude = latitude
|
||||
this.address = address
|
||||
this.time = time
|
||||
this.direction = direction
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
/**
|
||||
* 城市策略实体
|
||||
*/
|
||||
class Results(var cityStrategy: CityStrategy) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.zhidao.roadcondition.model
|
||||
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.mogo.commons.network.Utils
|
||||
import com.zhidao.roadcondition.base.BaseRepository
|
||||
import com.zhidao.roadcondition.net.HttpClient
|
||||
import com.zhidao.roadcondition.util.LocationUtil
|
||||
|
||||
class StrategyServiceModel : BaseRepository() {
|
||||
|
||||
suspend fun getCityStrategy(): BaseResponse<Results> {
|
||||
return apiCall {
|
||||
var map = hashMapOf<String, String>()
|
||||
map["sn"] = Utils.getSn()
|
||||
val locInfo = LocationUtil.getInstance().getLocationInfo()
|
||||
map["data"] = Gson().toJson(
|
||||
StrategyRequest(
|
||||
locInfo.longitude,
|
||||
locInfo.latitude,
|
||||
locInfo.cityCode
|
||||
)
|
||||
)
|
||||
HttpClient.getInstance().getHttpApi().getCityStrategy(map)
|
||||
}
|
||||
}
|
||||
|
||||
// suspend fun getAuthorization(): BaseResponse<Any> {
|
||||
// return apiCall {
|
||||
// HttpClient.getInstance().getHttpApi().getAuthorization(getSn())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// suspend fun getAllConfig(): BaseResponse<CommonConfig> {
|
||||
// return apiCall {
|
||||
// var map = hashMapOf<String, String>()
|
||||
// map["sn"] = getSn()
|
||||
// HttpClient.getInstance().getHttpApi()
|
||||
// .getAllCommonConfig(map)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// suspend fun getSplashConfig(): BaseResponse<SplashConfig> {
|
||||
// return apiCall {
|
||||
// var splashConfigRequest =
|
||||
// SplashConfigRequest("1", "1")
|
||||
// var splashBodyStr = Gson().toJson(splashConfigRequest)
|
||||
//
|
||||
// HttpClient.getInstance().getHttpApi()
|
||||
// .getSplashConfig(
|
||||
// mapOf(
|
||||
// "sn" to getSn(),
|
||||
// "data" to splashBodyStr
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
suspend fun uploadInformation(informationBody: InformationBody): BaseResponse<Any> {
|
||||
return apiCall {
|
||||
var informationBodyStr = Gson().toJson(informationBody)
|
||||
Log.d("MainServiceController", "uploadInformation informationBody = " + informationBodyStr)
|
||||
HttpClient.getInstance().getHttpApi()
|
||||
.uploadInformation(mapOf("sn" to Utils.getSn(), "data" to informationBodyStr))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zhidao.roadcondition.model.proxy
|
||||
|
||||
import androidx.annotation.IntDef
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
|
||||
const val INFO_TYPE_GONE = 0
|
||||
const val INFO_TYPE_SHOW = 1
|
||||
|
||||
|
||||
@IntDef(INFO_TYPE_GONE, INFO_TYPE_SHOW)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
annotation class ActiveInfoType
|
||||
|
||||
fun isActiveShow(@ActiveInfoType type: Int): Boolean {
|
||||
return when (type) {
|
||||
INFO_TYPE_GONE -> false
|
||||
INFO_TYPE_SHOW -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.zhidao.roadcondition.model.proxy
|
||||
|
||||
import androidx.annotation.IntDef
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
|
||||
const val INFO_TYPE_IMG = 0 //图片
|
||||
const val INFO_TYPE_VIDEO = 1
|
||||
const val INFO_TYPE_VOICE = 2
|
||||
const val INFO_TYPE_WORD = 3
|
||||
|
||||
|
||||
@IntDef(INFO_TYPE_IMG, INFO_TYPE_VIDEO, INFO_TYPE_VOICE, INFO_TYPE_WORD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
annotation class InformationsType
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import android.util.Log
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
|
||||
class CommonInterceptor : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val oldRequest = chain.request()
|
||||
val newRequest = oldRequest.newBuilder()
|
||||
Log.d("CommonInterceptor","addHeader")
|
||||
newRequest.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
return chain.proceed(newRequest.build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import com.zhidao.roadcondition.exception.ApiException
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
/**
|
||||
* 后续考虑加入Lifecycle管理,暂时不做扩展
|
||||
*/
|
||||
class CoroutineChain {
|
||||
|
||||
internal class CoroutineLifecycleListener(private val deferred: Deferred<*>, private val lifecycle: Lifecycle) :
|
||||
LifecycleObserver {
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
fun cancelCoroutine() {
|
||||
if (deferred.isActive) {
|
||||
deferred.cancel()
|
||||
}
|
||||
lifecycle.removeObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
infix fun LifecycleOwner.start(start: (() -> Unit)): LifecycleOwner {
|
||||
start()
|
||||
return this
|
||||
}
|
||||
|
||||
infix fun <T> LifecycleOwner.request(loader: suspend () -> T): Deferred<T> {
|
||||
return request(loader, true)
|
||||
}
|
||||
|
||||
fun <T> LifecycleOwner.request(loader: suspend () -> T, needAutoCancel: Boolean = true): Deferred<T> {
|
||||
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
||||
loader()
|
||||
}
|
||||
if (needAutoCancel) {
|
||||
lifecycle.addObserver(CoroutineLifecycleListener(deferred, lifecycle))
|
||||
}
|
||||
return deferred
|
||||
}
|
||||
|
||||
fun <T> Deferred<T>.then(
|
||||
onSuccess: suspend (T) -> Unit,
|
||||
onError: suspend (java.lang.Exception) -> Unit,
|
||||
onComplete: (() -> Unit)? = null
|
||||
): Job {
|
||||
return GlobalScope.launch(context = Main) {
|
||||
try {
|
||||
val result = this@then.await()
|
||||
onSuccess(result)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
when (e) {
|
||||
is UnknownHostException -> onError?.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
is TimeoutException -> onError?.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
is SocketTimeoutException -> onError?.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
else -> onError(e)
|
||||
}
|
||||
} finally {
|
||||
onComplete?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.zhidao.roadcondition.exception.ApiException
|
||||
import com.zhidao.roadcondition.exception.ApiException.Companion.NETWORK_API_EXCEPTION
|
||||
import com.zhidao.roadcondition.exception.ApiException.Companion.NULL_REQUEST_DATA_API_EXCEPTION
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
import kotlinx.coroutines.*
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
class Request<T> {
|
||||
private lateinit var loader: suspend () -> T
|
||||
|
||||
private var start: (() -> Unit)? = null
|
||||
|
||||
private var onSuccess: ((T) -> Unit)? = null
|
||||
|
||||
private var onError: ((java.lang.Exception) -> Unit)? = null
|
||||
|
||||
private var onComplete: (() -> Unit)? = null
|
||||
|
||||
private var addLifecycle: LifecycleOwner? = null
|
||||
|
||||
|
||||
infix fun loader(loader: suspend () -> T) {
|
||||
this.loader = loader
|
||||
}
|
||||
|
||||
infix fun start(start: (() -> Unit)?) {
|
||||
this.start = start
|
||||
}
|
||||
|
||||
infix fun onSuccess(onSuccess: ((T) -> Unit)?) {
|
||||
this.onSuccess = onSuccess
|
||||
}
|
||||
|
||||
infix fun onError(onError: ((java.lang.Exception) -> Unit)?) {
|
||||
this.onError = onError
|
||||
}
|
||||
|
||||
infix fun onComplete(onComplete: (() -> Unit)?) {
|
||||
this.onComplete = onComplete
|
||||
}
|
||||
|
||||
infix fun addLifecycle(addLifecycle: LifecycleOwner?) {
|
||||
this.addLifecycle = addLifecycle
|
||||
}
|
||||
|
||||
fun request() {
|
||||
request(addLifecycle)
|
||||
}
|
||||
|
||||
fun request(addLifecycle: LifecycleOwner?) {
|
||||
|
||||
GlobalScope.launch(context = Dispatchers.Main) {
|
||||
|
||||
start?.invoke()
|
||||
try {
|
||||
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
||||
loader()
|
||||
}
|
||||
addLifecycle?.apply {
|
||||
lifecycle.addObserver(
|
||||
CoroutineChain.CoroutineLifecycleListener(
|
||||
deferred,
|
||||
lifecycle
|
||||
)
|
||||
)
|
||||
}
|
||||
val result = deferred.await()
|
||||
if (result != null && result is BaseResponse<*>) {
|
||||
if (result.code == 0) {
|
||||
onSuccess?.invoke(result)
|
||||
} else {
|
||||
throw ApiException(result.code, result.msg)
|
||||
}
|
||||
} else {
|
||||
throw NULL_REQUEST_DATA_API_EXCEPTION
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
//数据打点
|
||||
when (e) {
|
||||
is UnknownHostException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
is TimeoutException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
is SocketTimeoutException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
else -> onError?.invoke(java.lang.Exception(e.message))
|
||||
}
|
||||
} finally {
|
||||
onComplete?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> request(buildRequest: Request<T>.() -> Unit) {
|
||||
Request<T>().apply(buildRequest).request()
|
||||
}
|
||||
|
||||
inline fun <T> LifecycleOwner.request(buildRequest: Request<T>.() -> Unit) {
|
||||
Request<T>().apply(buildRequest).request(this)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
import com.zhidao.roadcondition.model.CommonConfig
|
||||
import com.zhidao.roadcondition.model.Results
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.http.*
|
||||
|
||||
/**
|
||||
* 接口声明
|
||||
*/
|
||||
interface HttpApi {
|
||||
//获取城市策略
|
||||
@FormUrlEncoded
|
||||
@POST("yycp-geo-fence-carService/car/carStrategy/no/getCityStrategy/v1")
|
||||
suspend fun getCityStrategy(@FieldMap cityStrategy: Map<String, String>): BaseResponse<Results>
|
||||
|
||||
//上报情报数据
|
||||
@FormUrlEncoded
|
||||
@POST("/deva/car/path/no/addInfomation/v2")
|
||||
suspend fun uploadInformation(@FieldMap information: Map<String, String>): BaseResponse<Any>
|
||||
|
||||
//获取所有配置
|
||||
@GET("dataService/car/customConfig/no/getAll/v1")
|
||||
suspend fun getAllCommonConfig(@QueryMap commonConfigBody: Map<String, String>):BaseResponse<CommonConfig>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.roadcondition.constant.HttpConstants
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class HttpClient {
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_CONNECT_TIME = 30L
|
||||
const val DEFAULT_WRITE_TIMEOUT = 30L
|
||||
const val DEFAULT_READ_TIMEOUT = 30L
|
||||
|
||||
const val COMMON_PARAM_SN = "sn"
|
||||
|
||||
private var baseUrlClientMap = HashMap<String, HttpClient>()
|
||||
|
||||
fun getInstance(): HttpClient {
|
||||
var baseUrl = HttpConstants.getBaseUrl()
|
||||
var httpClient = baseUrlClientMap[baseUrl]
|
||||
if (httpClient == null) {
|
||||
synchronized(HttpClient::class.java) {
|
||||
if (httpClient == null) {
|
||||
httpClient = HttpClient(baseUrl)
|
||||
baseUrlClientMap[baseUrl] = httpClient!!
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpClient!!
|
||||
}
|
||||
|
||||
fun getInstance(baseUrl: String): HttpClient {
|
||||
var httpClient = baseUrlClientMap[baseUrl]
|
||||
if (httpClient == null) {
|
||||
synchronized(HttpClient::class.java) {
|
||||
if (httpClient == null) {
|
||||
httpClient = HttpClient(baseUrl)
|
||||
baseUrlClientMap[baseUrl] = httpClient!!
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpClient!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private lateinit var retrofit: Retrofit
|
||||
private lateinit var httpApi: HttpApi
|
||||
|
||||
private constructor(baseUrl: String) {
|
||||
retrofit = Retrofit.Builder()
|
||||
.client(getOkHttpClient())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.baseUrl(baseUrl)
|
||||
.build()
|
||||
httpApi = retrofit.create(HttpApi::class.java)
|
||||
}
|
||||
|
||||
fun getHttpApi(): HttpApi {
|
||||
return httpApi
|
||||
}
|
||||
|
||||
private fun getOkHttpClient(): OkHttpClient {
|
||||
val httpLoggingInterceptor = HttpLoggingInterceptor()
|
||||
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||
val cacheFile = File(AbsMogoApplication.getApp().applicationContext.cacheDir, "cache")
|
||||
val cache = Cache(cacheFile, 1024 * 1024 * 50)
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.cache(cache)
|
||||
.connectTimeout(DEFAULT_CONNECT_TIME, TimeUnit.SECONDS)
|
||||
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
.writeTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS)
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import androidx.annotation.NonNull
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.internal.Util
|
||||
import okio.BufferedSink
|
||||
|
||||
class PostCommonBody : RequestBody {
|
||||
|
||||
companion object {
|
||||
val CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8")
|
||||
val charset = Util.UTF_8
|
||||
|
||||
fun create(@NonNull content: String): RequestBody {
|
||||
return PostCommonBody(content)
|
||||
}
|
||||
}
|
||||
|
||||
private var content: String
|
||||
|
||||
constructor(@NonNull content: String) {
|
||||
this.content = content
|
||||
}
|
||||
|
||||
fun getContent(): String {
|
||||
return content
|
||||
}
|
||||
|
||||
override fun contentType(): MediaType? {
|
||||
return CONTENT_TYPE
|
||||
}
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
if (content.isNullOrEmpty()) {
|
||||
throw NullPointerException("content == null")
|
||||
}
|
||||
val bytes = content.toByteArray(charset)
|
||||
Util.checkOffsetAndCount(bytes!!.size.toLong(), 0, bytes!!.size.toLong())
|
||||
sink.write(bytes, 0, bytes!!.size)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import com.zhidao.roadcondition.constant.HttpConstants
|
||||
import com.zhidao.roadcondition.exception.ApiException
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
import io.reactivex.functions.Function
|
||||
|
||||
class ResponseFunction<T> : Function<BaseResponse<T>, T> {
|
||||
|
||||
private var baseUrl: String = ""
|
||||
|
||||
constructor() {
|
||||
this.baseUrl = HttpConstants.getBaseUrl()
|
||||
}
|
||||
|
||||
constructor(baseUrl: String) {
|
||||
this.baseUrl = baseUrl
|
||||
}
|
||||
|
||||
override fun apply(t: BaseResponse<T>): T {
|
||||
if (t == null || !t.isSuccess(baseUrl)) {
|
||||
throw ApiException(t.code, t.msg)
|
||||
}
|
||||
return t.result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zhidao.roadcondition.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.zhidao.roadcondition.service.MainService
|
||||
|
||||
class ShareRoadReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.d("MainService", "ShareRoadReceiver ------> intent.action = " + intent.action)
|
||||
if (intent.action == "com.zhidao.share.roadcondition.action") {
|
||||
var type = intent.getStringExtra("type")
|
||||
Log.e("MainService", "ShareRoadReceiver type ----> $type ----> 此方法已经废弃了,无法调起服务")
|
||||
// MainService.launchService(context, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.hw.videoprocessor.VideoProcessor
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.mogo.utils.NetworkUtils
|
||||
import com.zhidao.auto.carcorder.callback.TakePhotoCallback
|
||||
import com.zhidao.auto.carcorder.callback.TakeVideoCallback
|
||||
import com.zhidao.auto.carcorder.controller.ZdCarCoderController
|
||||
import com.zhidao.roadcondition.BuildConfig
|
||||
import com.zhidao.roadcondition.constant.*
|
||||
import com.zhidao.roadcondition.event.GetImageSuccessEvent
|
||||
import com.zhidao.roadcondition.event.LatLngStickyEventBus
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_IMG
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_VIDEO
|
||||
import com.zhidao.roadcondition.util.*
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyMaxSpeed
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyMinSpeed
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyType
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @description 记录仪相关操作
|
||||
*
|
||||
* @author lixiaopeng
|
||||
* @since 2019-10-30
|
||||
*/
|
||||
object CarCorderController : TakePhotoCallback, TakeVideoCallback {
|
||||
private lateinit var zdCarCoderController: ZdCarCoderController
|
||||
val TAG: String = this.javaClass.simpleName
|
||||
var outputVideoPath: String = ""
|
||||
var mType: String = "" //1 上报拥堵, 2 封路和查车
|
||||
var mainInfoId: Long = 0
|
||||
var mFromType: String = ""
|
||||
|
||||
private var getVideoFailed: (() -> Unit)? = null
|
||||
private var interceptors: ArrayList<TakePhotoInterceptor> = ArrayList(1)
|
||||
|
||||
fun getVideoFailed(getVideoFailed: (() -> Unit)) {
|
||||
this.getVideoFailed = getVideoFailed
|
||||
}
|
||||
|
||||
fun registerTakePhotoInterceptor(interceptor: TakePhotoInterceptor) {
|
||||
interceptor?.apply {
|
||||
interceptors.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterTakePhotoInterceptor(interceptor: TakePhotoInterceptor) {
|
||||
interceptor?.apply {
|
||||
interceptors.remove(interceptor)
|
||||
}
|
||||
}
|
||||
|
||||
fun initCarCorderController() {
|
||||
zdCarCoderController =
|
||||
ZdCarCoderController.getInstance(AbsMogoApplication.getApp().applicationContext)
|
||||
zdCarCoderController.addCallback(this)
|
||||
zdCarCoderController.addVideoCallback(this)
|
||||
zdCarCoderController.init()
|
||||
}
|
||||
|
||||
fun takePhoto(
|
||||
photoType: Int,
|
||||
cameraId: Int,
|
||||
haveVoice: Boolean,
|
||||
isCustom: Boolean = false,
|
||||
type: String,
|
||||
mainInfoId: Long,
|
||||
fromType: String
|
||||
) {
|
||||
Log.d(TAG, "takePhoto ---------- type = $type --- mType = $mType ---fromType = $fromType")
|
||||
this.mType = type
|
||||
this.mainInfoId = mainInfoId
|
||||
this.mFromType = fromType
|
||||
CustomStatusHandler.offerPhotoStatus(isCustom)
|
||||
zdCarCoderController.takePhoto(photoType, cameraId, haveVoice)
|
||||
trackGetPhoto(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isCustom: 是否手动上传
|
||||
* @param id: 标志是哪一个上传
|
||||
*/
|
||||
fun takeVideo(
|
||||
cameraId: Int,
|
||||
duration: Int,
|
||||
isCustom: Boolean = false,
|
||||
id: Long = 0L,
|
||||
type: String,
|
||||
mainInfoId: Long,
|
||||
fromType: String
|
||||
) {
|
||||
Log.d(TAG, "takeVideo -------- type = $type")
|
||||
Log.d(TAG, "takeVideo -------- isCustom = $isCustom ---mFromType = $mFromType")
|
||||
this.mType = type
|
||||
this.mainInfoId = mainInfoId
|
||||
this.mFromType = fromType
|
||||
if (DebugConfig.getCarMachineType() == 0) { //自研车机
|
||||
outputVideoPath = getCompressVideoPath()
|
||||
CustomStatusHandler.offerVideoStatus(TakeEntity(isCustom, id))
|
||||
zdCarCoderController.takeVideo(cameraId, duration)
|
||||
trackGetVideo(1)
|
||||
} else { //比亚迪
|
||||
Log.d(TAG, "takeVideo ------ isnet = " + NetworkUtils.isConnected(AbsMogoApplication.getApp().applicationContext))
|
||||
// if (!NetworkUtils.isConnected(AbsMogoApplication.getApp().applicationContext)) {
|
||||
// TipToast.shortTip("分享失败,请检查网络")
|
||||
// } else {
|
||||
//失败了,传空地址,发起请求
|
||||
val entity = TakeEntity(isCustom, id)
|
||||
videoAndThumbMap["video"] = ""
|
||||
videoAndThumbMap["thumb"] = ""
|
||||
|
||||
CosStatusController().sendInformationDirectly(
|
||||
INFO_TYPE_VIDEO,
|
||||
videoAndThumbMap,
|
||||
mType,
|
||||
entity,
|
||||
mainInfoId
|
||||
)
|
||||
|
||||
//地图上打点
|
||||
taskAsync(3_000) {
|
||||
try {
|
||||
LatLngStickyEventBus.getInstance()
|
||||
.postSticky(GetImageSuccessEvent("", mType))
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
zdCarCoderController.release()
|
||||
interceptors?.clear()
|
||||
}
|
||||
|
||||
//拍照失败回调
|
||||
override fun onTakePhotoFail(photoType: Int, camera: Int) {
|
||||
trackGetPhoto(3)
|
||||
interceptors.forEach {
|
||||
it?.onTakePhotoFail(photoType, camera)
|
||||
}
|
||||
val isCustom = CustomStatusHandler.pollPhotoStatus()
|
||||
val entity = TakeEntity(isCustom, 0L)
|
||||
Log.e(TAG, "onTakePhotoFail -----mType = $mType --- isCustom = $isCustom")
|
||||
//语音播报 1:上报路况,2:交通检查,3:封路 默认 mType 应该为null
|
||||
if (mType.equals(TANLU_ROAD_CONGESTION) || mType.equals(TANLU_TRAFFIC_CHECK) || mType.equals(
|
||||
TANLU_ROAD_CLOSURE
|
||||
)
|
||||
|| mType.equals(TANLU_ROAD_CURRENT) || mType.equals(TANLU_ROAD_PONDING) || mType.equals(
|
||||
TANLU_ROAD_ICING
|
||||
)
|
||||
|| mType.equals(TANLU_ROAD_HEAVY_FOG) || mType.equals(TANLU_ROAD_ACCIDENT) || mType.equals(
|
||||
TANLU_ROAD_WORK
|
||||
)
|
||||
) {
|
||||
taskAsync(1_500) {
|
||||
try {
|
||||
// VoiceController.speakVoice("上报失败")
|
||||
// if (isCustom) {
|
||||
// sendGetInfoFailedReceiver(mType)
|
||||
// }
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
//获取图片失败也上报,图片不打点
|
||||
if (isCustom) {
|
||||
CosStatusController().sendInformationDirectly(
|
||||
INFO_TYPE_IMG,
|
||||
mutableMapOf("pic" to "" as String),
|
||||
mType,
|
||||
entity,
|
||||
mainInfoId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//拍照成功回调返回图片本地路径
|
||||
override fun onTakePhotoSuccess(photoType: Int, camera: Int, photoPath: String?) {
|
||||
trackGetPhoto(2)
|
||||
Log.d(TAG, "onTakePhotoSuccess -----mType = $mType --- mainInfoId = $mainInfoId")
|
||||
val isCustom = CustomStatusHandler.pollPhotoStatus()
|
||||
val entity = TakeEntity(isCustom, 0L)
|
||||
|
||||
if (!isCustom) {
|
||||
trackNormalEvent(CarNet_auto_upload, null)
|
||||
}
|
||||
|
||||
var interceptor = false
|
||||
interceptors.forEach {
|
||||
interceptor = it?.intercept()
|
||||
it?.onTakePhotoSuccess(photoType, camera, photoPath)
|
||||
}
|
||||
if (interceptor) {
|
||||
return
|
||||
}
|
||||
|
||||
var minSpeedPic =
|
||||
getStrategyMinSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"pic",
|
||||
getStrategyType("pic")
|
||||
)
|
||||
var maxSpeedPic =
|
||||
getStrategyMaxSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"pic",
|
||||
getStrategyType("pic")
|
||||
)
|
||||
var speed = LocationUtil.getInstance().getSpeed()
|
||||
|
||||
if (!TextUtils.isEmpty(mType)) {
|
||||
Log.d(TAG, "onTakePhotoSuccess mType != null")
|
||||
CosStatusController().uploadFile(mutableListOf(photoPath as String), entity, mType, mainInfoId, mFromType)
|
||||
} else {
|
||||
Log.d(TAG, "onTakePhotoSuccess mType == null")
|
||||
Log.d(
|
||||
TAG,
|
||||
"onTakePhotoSuccess maxSpeedPic = $maxSpeedPic ---> speed = $speed ---->minSpeedPic= $minSpeedPic"
|
||||
)
|
||||
if (maxSpeedPic == -1) {
|
||||
if (speed >= (Math.abs(minSpeedPic) / 3.6f)) {
|
||||
Log.d(TAG, "onTakePhotoSuccess abs =" + (Math.abs(minSpeedPic) / 3.6f))
|
||||
CosStatusController().uploadFile(
|
||||
mutableListOf(photoPath as String),
|
||||
entity,
|
||||
mType,
|
||||
mainInfoId,
|
||||
mFromType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (minSpeedPic > 0 && maxSpeedPic > 0) {
|
||||
Log.d(TAG, "onTakePhotoSuccess minSpeedPic > 0 -- speed = $speed")
|
||||
if ((speed >= (minSpeedPic / 3.6f)) && speed <= (maxSpeedPic / 3.6f)) {
|
||||
CosStatusController().uploadFile(
|
||||
mutableListOf(photoPath as String),
|
||||
entity,
|
||||
mType,
|
||||
mainInfoId,
|
||||
mFromType
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取视频成功
|
||||
override fun onTakeVideoSuccess(camera: Int, videoPath: String?) {
|
||||
var thumbnailPath =
|
||||
AbsMogoApplication.getApp().applicationContext.filesDir.parent + File.separator + "Thumbnail${System.currentTimeMillis()}.jpg"
|
||||
var isSuccess = getVideoThumbnail(videoPath!!, thumbnailPath)
|
||||
Log.d(
|
||||
TAG,
|
||||
"getVideo onTakeVideoSuccess===$videoPath -----> isSuccess= $isSuccess ----> mType = $mType --- mainInfoId = $mainInfoId"
|
||||
)
|
||||
|
||||
val entity = CustomStatusHandler.pollVideoStatus()
|
||||
if (!entity?.isCustom) {
|
||||
trackNormalEvent(CarNet_auto_upload_video, null)
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
var minSpeedVideo = getStrategyMinSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext, "video",
|
||||
getStrategyType("video")
|
||||
)
|
||||
var maxSpeedVideo = getStrategyMaxSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext, "video",
|
||||
getStrategyType("video")
|
||||
)
|
||||
var speed = LocationUtil.getInstance().getSpeed()
|
||||
//TODO
|
||||
if (BuildConfig.DEBUG) {
|
||||
//获取视频以及缩略图成功,开始上报
|
||||
compressVideo(videoPath, thumbnailPath, entity)
|
||||
return
|
||||
}
|
||||
|
||||
if (entity?.isCustom) {
|
||||
compressVideo(videoPath, thumbnailPath, entity)
|
||||
} else {
|
||||
Log.d(
|
||||
TAG,
|
||||
"onTakeVideoSuccess maxSpeedVideo = $maxSpeedVideo --->speed= $speed + minSpeedVideo = $minSpeedVideo"
|
||||
)
|
||||
if (maxSpeedVideo == -1) {
|
||||
Log.d(TAG, "onTakeVideoSuccess 111 abs =" + (Math.abs(minSpeedVideo) / 3.6f))
|
||||
if (speed >= (Math.abs(minSpeedVideo) / 3.6f)) {
|
||||
//获取视频以及缩略图成功,开始上报
|
||||
compressVideo(videoPath, thumbnailPath, entity)
|
||||
}
|
||||
}
|
||||
|
||||
if (minSpeedVideo > 0 && maxSpeedVideo > 0) {
|
||||
Log.d(TAG, "onTakeVideoSuccess minSpeedVideo > 0 -- speed = $speed")
|
||||
if ((speed >= (minSpeedVideo / 3.6f)) && speed <= (maxSpeedVideo / 3.6f)) {
|
||||
compressVideo(videoPath, thumbnailPath, entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trackGetVideo(2)
|
||||
}
|
||||
}
|
||||
|
||||
var videoAndThumbMap: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
//获取视频失败
|
||||
override fun onTakeVideoFail(camera: Int) {
|
||||
trackGetVideo(3)
|
||||
Log.e(TAG, "getVideo onTakeVideoFail")
|
||||
getVideoFailed?.invoke()
|
||||
val entity = CustomStatusHandler.pollVideoStatus()
|
||||
InformationUploadController.release(entity?.id)
|
||||
Log.e(TAG, "getVideo onTakeVideoFail entity?.isCustom =" + entity?.isCustom)
|
||||
if (entity?.isCustom) {
|
||||
// sendGetInfoFailedReceiver(mType)
|
||||
}
|
||||
|
||||
//失败了,传空地址,发起请求
|
||||
videoAndThumbMap["video"] = ""
|
||||
videoAndThumbMap["thumb"] = ""
|
||||
|
||||
CosStatusController().sendInformationDirectly(
|
||||
INFO_TYPE_VIDEO,
|
||||
videoAndThumbMap,
|
||||
mType,
|
||||
entity,
|
||||
mainInfoId
|
||||
)
|
||||
|
||||
//地图上打点
|
||||
taskAsync(3_000) {
|
||||
try {
|
||||
LatLngStickyEventBus.getInstance().postSticky(GetImageSuccessEvent("", mType))
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩视频并且上传
|
||||
*/
|
||||
fun compressVideo(videoPath: String, thumbnailPath: String, entity: TakeEntity) {
|
||||
Log.d(
|
||||
TAG,
|
||||
"outputVideoPath = " + outputVideoPath + ">> videoPath=" + videoPath + " isCustom = ${entity?.isCustom}"
|
||||
)
|
||||
var startTime = System.currentTimeMillis()
|
||||
Thread(Runnable {
|
||||
try {
|
||||
VideoProcessor.processor(AbsMogoApplication.getApp().applicationContext)
|
||||
.input(videoPath)
|
||||
.output(outputVideoPath)
|
||||
.removeAudio(true)
|
||||
.outWidth(1920)
|
||||
.outHeight(1080)
|
||||
.bitrate(2000 * 1024)
|
||||
.frameRate(25)
|
||||
.process()
|
||||
Log.d(TAG, "compress cost time =" + (System.currentTimeMillis() - startTime))
|
||||
CosStatusController().uploadFile(
|
||||
mutableListOf(outputVideoPath, thumbnailPath),
|
||||
entity,
|
||||
mType,
|
||||
mainInfoId,
|
||||
mFromType
|
||||
)
|
||||
//删除压缩前的视频
|
||||
deletePicFile(videoPath)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "compressVideo e = $e")
|
||||
//删除压缩前的视频
|
||||
deletePicFile(videoPath)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}).start()
|
||||
}
|
||||
|
||||
override fun onTakePhotoCancel(photoType: Int, camera: Int) {
|
||||
Log.d(TAG, "onTakePhotoCancel -----photoType = $photoType")
|
||||
}
|
||||
|
||||
override fun onTakeVideoCancel(camera: Int) {
|
||||
Log.d(TAG, "onTakeVideoCancel -----camera = $camera")
|
||||
}
|
||||
|
||||
//获取图片
|
||||
private fun trackGetPhoto(type: Int) {
|
||||
trackNormalEvent(
|
||||
CarNet_Get_Picture, mutableMapOf("type" to type),
|
||||
AbsMogoApplication.getApp().applicationContext
|
||||
)
|
||||
}
|
||||
|
||||
//获取视频
|
||||
private fun trackGetVideo(type: Int) {
|
||||
trackNormalEvent(
|
||||
CarNet_Get_Video, mutableMapOf("type" to type),
|
||||
AbsMogoApplication.getApp().applicationContext
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.util.Log
|
||||
import com.zhidao.cosupload.callback.CosStatusCallback
|
||||
import com.zhidao.cosupload.callback.CosStatusCallbackManager
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-25
|
||||
*
|
||||
*/
|
||||
object CosCallbackMapController : CosStatusCallback {
|
||||
|
||||
val TAG = "CosCallbackMapController"
|
||||
|
||||
val map: MutableMap<String, CosStatusCallback> = mutableMapOf()
|
||||
|
||||
var uploadFailed: (() -> Unit)? = null
|
||||
|
||||
var mainService: MainService? = null
|
||||
fun init(mainService: MainService) {
|
||||
this.mainService = mainService
|
||||
CosStatusCallbackManager.getInstance().register(this)
|
||||
}
|
||||
|
||||
fun uploadFailed(uploadFailed: (() -> Unit)) {
|
||||
this.uploadFailed = uploadFailed
|
||||
}
|
||||
|
||||
fun registerCallback(paths: List<String>, callback: CosStatusCallback) {
|
||||
paths?.let { list ->
|
||||
list.forEach { path ->
|
||||
path?.let {
|
||||
map[path] = callback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterCallback(path: String?) {
|
||||
path?.let {
|
||||
map.remove(path)
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterCallbacks(paths: Map<String, String>?) {
|
||||
paths?.let {
|
||||
it?.keys?.let { keys ->
|
||||
keys.forEach { path ->
|
||||
unregisterCallback(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartUpload(eventId: String?, localPath: String?) {
|
||||
map[localPath]?.let {
|
||||
it.onStartUpload(eventId, localPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun uploadCosFailed(cosPath: String?, eventId: String?, localPath: String?) {
|
||||
map[localPath]?.let {
|
||||
it.uploadCosFailed(cosPath, eventId, localPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun uploadCosCompleted(
|
||||
cosPath: String?,
|
||||
eventId: String?,
|
||||
downloadUrl: String?,
|
||||
localPath: String?
|
||||
) {
|
||||
map[localPath]?.let {
|
||||
it.uploadCosCompleted(cosPath, eventId, downloadUrl, localPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(localPath: String?, progress: Float) {
|
||||
map[localPath]?.let {
|
||||
it.onProgress(localPath, progress)
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
CosStatusCallbackManager.getInstance().unregister(this)
|
||||
map.clear()
|
||||
uploadFailed = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.cosupload.DbPriorityConfig
|
||||
import com.zhidao.cosupload.callback.CosStatusCallback
|
||||
import com.zhidao.cosupload.manager.CosUploadManagerImpl
|
||||
import com.zhidao.roadcondition.constant.*
|
||||
import com.zhidao.roadcondition.event.GetImageSuccessEvent
|
||||
import com.zhidao.roadcondition.event.LatLngStickyEventBus
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_IMG
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_VIDEO
|
||||
import com.zhidao.roadcondition.util.CarNet_Cos_Upload
|
||||
import com.zhidao.roadcondition.util.LocationUtil
|
||||
import com.zhidao.roadcondition.util.deletePicFile
|
||||
import com.zhidao.roadcondition.util.trackNormalEvent
|
||||
|
||||
/**
|
||||
* @description cos上传操作
|
||||
*
|
||||
* @author lixiaopeng
|
||||
* @since 2019-10-30
|
||||
*/
|
||||
class CosStatusController : CosStatusCallback {
|
||||
val TAG: String = this.javaClass.simpleName
|
||||
//存储单次请求的视频和缩略图url
|
||||
var videoAndThumbMap: MutableMap<String, String> = mutableMapOf()
|
||||
//图片上传的eventId
|
||||
lateinit var mPicEventId: String
|
||||
private var isRetry = false //是否重试上传过图片
|
||||
|
||||
private var mainServiceHttpModel = MainServiceController()
|
||||
|
||||
private lateinit var entity: TakeEntity
|
||||
|
||||
private var mType: String = ""
|
||||
private var mainInfoId: Long = 0
|
||||
private var mFromType: String = ""
|
||||
|
||||
//上传文件
|
||||
fun uploadFile(picPath: MutableList<String>, entity: TakeEntity, type: String, mainInfoId: Long, fromType: String) {
|
||||
CosCallbackMapController.registerCallback(picPath, this)
|
||||
// CosLogger.setLogStatus(true)
|
||||
|
||||
this.entity = entity
|
||||
this.mType = type
|
||||
this.mainInfoId = mainInfoId
|
||||
this.mFromType = fromType;
|
||||
Log.d(TAG, "uploadFile type===$type ---- mainInfoId =$mainInfoId ----mFromType = $mFromType ---- picPath = $picPath ")
|
||||
trackUploadCos(3)
|
||||
if (picPath.contains("backPic")) return
|
||||
//参数说明: paths:本地文件路径;(注:上传的本地路径不要重复);config:文件上传的优先级
|
||||
mPicEventId =
|
||||
CosUploadManagerImpl.getInstance(AbsMogoApplication.getApp().applicationContext).eventId
|
||||
CosUploadManagerImpl.getInstance(AbsMogoApplication.getApp().applicationContext)
|
||||
.upload(picPath, mPicEventId, DbPriorityConfig.PRIORITY_HIGH)
|
||||
}
|
||||
|
||||
|
||||
override fun onStartUpload(eventId: String?, localPath: String?) {
|
||||
}
|
||||
|
||||
private fun sendGetInfoFailedReceiver(type: String) {
|
||||
Log.d(CarCorderController.TAG, "sendGetInfoFailedReceiver ------>")
|
||||
var intent = Intent()
|
||||
intent.action = "com.zhidao.roadcondition.getinfo.failed"
|
||||
intent.putExtra("type", type)
|
||||
AbsMogoApplication.getApp().applicationContext.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
override fun uploadCosFailed(cosPath: String?, eventId: String?, localPath: String?) {
|
||||
Log.d(TAG, "uploadCosFailed = $localPath")
|
||||
trackUploadCos(2)
|
||||
//语音播报 1:上报路况,2:交通检查,3:封路 默认 mType 应该为null
|
||||
if (CarCorderController.mType.equals(TANLU_ROAD_CONGESTION) || CarCorderController.mType.equals(
|
||||
TANLU_TRAFFIC_CHECK
|
||||
) || CarCorderController.mType.equals(TANLU_ROAD_CLOSURE)
|
||||
|| CarCorderController.mType.equals(TANLU_ROAD_CURRENT) || CarCorderController.mType.equals(
|
||||
TANLU_ROAD_PONDING
|
||||
) || CarCorderController.mType.equals(TANLU_ROAD_ICING)
|
||||
|| CarCorderController.mType.equals(TANLU_ROAD_HEAVY_FOG) || CarCorderController.mType.equals(
|
||||
TANLU_ROAD_ACCIDENT
|
||||
) || CarCorderController.mType.equals(TANLU_ROAD_WORK)
|
||||
) {
|
||||
// VoiceController.speakVoice("cos上报失败")
|
||||
Log.d(TAG, "uploadCosFailed mType = $mType")
|
||||
if (entity?.isCustom && mFromType != UPLOAD_FROM_STRATEGY_ACCIDENT_AUTO) {
|
||||
sendGetInfoFailedReceiver("100")
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRetry) {
|
||||
isRetry = true
|
||||
// taskAsync(30_000) { //去掉重试
|
||||
// try {
|
||||
// uploadFile(mutableListOf(localPath as String), entity, mType)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
if (localPath!!.endsWith("mp4") || localPath!!.contains("Thumbnail")) {
|
||||
CosCallbackMapController.uploadFailed?.invoke()
|
||||
}
|
||||
CosCallbackMapController.unregisterCallback(localPath)
|
||||
InformationUploadController.release(entity?.id)
|
||||
// deletePicFile(localPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun uploadCosCompleted(
|
||||
cosPath: String?,
|
||||
eventId: String?,
|
||||
downloadUrl: String?,
|
||||
localPath: String?
|
||||
) {
|
||||
Log.d(TAG, "uploadFile mType= $mType")
|
||||
Log.d(TAG, "uploadCosCompleted localPath = $localPath")
|
||||
Log.d(TAG, "uploadCosCompleted downloadUrl = $downloadUrl")
|
||||
Log.d(TAG, "uploadCosCompleted cosPath = $cosPath")
|
||||
trackUploadCos(1)
|
||||
if (localPath!!.endsWith("mp4") || localPath!!.contains("Thumbnail")) {
|
||||
//如果是视频文件或者缩略图文件
|
||||
if (localPath.endsWith("mp4")) {
|
||||
videoAndThumbMap["video"] = downloadUrl!!
|
||||
Log.i(TAG, "videoAndThumbMap add mp4")
|
||||
} else {
|
||||
videoAndThumbMap["thumb"] = downloadUrl!!
|
||||
Log.i(TAG, "videoAndThumbMap add thumb")
|
||||
}
|
||||
Log.d(TAG, "videoAndThumbMap ${videoAndThumbMap}")
|
||||
if (videoAndThumbMap.size == 2) {
|
||||
Log.d(TAG, "videoAndThumbMap.size == 2 ")
|
||||
var locationInfo = LocationUtil.getInstance().getLocationInfo()
|
||||
val locationStr: String = Gson().toJson(locationInfo)
|
||||
Log.d(TAG, "locationStr = " + locationStr)
|
||||
//如果失败,需要提示失败弹框
|
||||
if (locationInfo.address.isNullOrEmpty() || locationInfo.cityName.isNullOrEmpty() || locationInfo.cityCode.isNullOrEmpty()
|
||||
|| locationInfo.latitude == 0.0 || locationInfo.areaName.isNullOrEmpty() || locationInfo.street.isNullOrEmpty()
|
||||
|| locationInfo.areaCode.isNullOrEmpty() || locationInfo.provinceName.isNullOrEmpty()
|
||||
) {
|
||||
if (entity?.isCustom && mFromType != UPLOAD_FROM_STRATEGY_ACCIDENT_AUTO) {
|
||||
sendGetInfoFailedReceiver("100")
|
||||
}
|
||||
} else {
|
||||
//分享成功,并打点,如果是上报拥堵,需要takeVideo
|
||||
LatLngStickyEventBus.getInstance()
|
||||
.postSticky(GetImageSuccessEvent(downloadUrl, mType))
|
||||
//上传录像以及缩略图成功
|
||||
sendInformation(INFO_TYPE_VIDEO, videoAndThumbMap)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//上传图片成功, 如果是上报路况,直接上传,TODO
|
||||
Log.d(TAG, "uploadCosCompleted 分享成功 ----mType = $mType")
|
||||
// if (mType.equals("1") || mType.equals("-1")) {
|
||||
sendInformationDirectly(
|
||||
INFO_TYPE_IMG,
|
||||
mutableMapOf("pic" to downloadUrl as String),
|
||||
mType,
|
||||
entity,
|
||||
mainInfoId
|
||||
)
|
||||
// }
|
||||
}
|
||||
Log.d(TAG, "delete file: ${localPath!!}")
|
||||
CosCallbackMapController.unregisterCallback(localPath)
|
||||
deletePicFile(localPath)
|
||||
}
|
||||
|
||||
private fun sendInformation(type: Int, map: Map<String, String>) {
|
||||
Log.d(TAG, "isCustomSend = ${entity?.isCustom}")
|
||||
// if (entity?.isCustom) {
|
||||
// InformationUploadController.cosResourceReady(type, map, entity?.isCustom, entity?.id) {
|
||||
// CosCallbackMapController.mainService?.sendCustomResult(it)
|
||||
// }
|
||||
// } else {
|
||||
sendInformationDirectly(type, map, mType, entity, mainInfoId)
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 被动上报时直接上报,不用等待、选择情报类型
|
||||
*/
|
||||
fun sendInformationDirectly(
|
||||
type: Int,
|
||||
map: Map<String, String>,
|
||||
poiType: String,
|
||||
entity: TakeEntity,
|
||||
mainInfoId: Long
|
||||
) {
|
||||
Log.d(TAG, "sendInformationDirectly isCustomSend = ${entity?.isCustom}")
|
||||
Log.d(TAG, "sendInformationDirectly poiType= $poiType ---- mainInfoId= $mainInfoId")
|
||||
mainServiceHttpModel.sendInformationMessage(
|
||||
type = type,
|
||||
url = map,
|
||||
isCustom = entity?.isCustom,
|
||||
poiType = poiType,
|
||||
mainInfoId = mainInfoId
|
||||
) { success ->
|
||||
CosCallbackMapController.unregisterCallbacks(map)
|
||||
CosCallbackMapController.mainService?.let {
|
||||
CosCallbackMapController.mainService?.sendCustomResult(success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(localPath: String?, progress: Float) {
|
||||
}
|
||||
|
||||
//上传COS
|
||||
private fun trackUploadCos(type: Int) {
|
||||
trackNormalEvent(
|
||||
CarNet_Cos_Upload, mutableMapOf("type" to type),
|
||||
AbsMogoApplication.getApp().applicationContext
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-25
|
||||
*
|
||||
* 拍照、拍视频手动、被动状态队列
|
||||
*/
|
||||
object CustomStatusHandler {
|
||||
|
||||
val takePhotoStatusQueue: Queue<Boolean> = ArrayDeque(5)
|
||||
val takeVideoStatusQueue: Queue<TakeEntity> = ArrayDeque(5)
|
||||
|
||||
fun offerPhotoStatus(status: Boolean) {
|
||||
takePhotoStatusQueue.offer(status)
|
||||
}
|
||||
|
||||
fun pollPhotoStatus() = takePhotoStatusQueue.poll() ?: false
|
||||
|
||||
fun offerVideoStatus(entity: TakeEntity) {
|
||||
takeVideoStatusQueue.offer(entity)
|
||||
}
|
||||
|
||||
fun pollVideoStatus(): TakeEntity = takeVideoStatusQueue.poll()
|
||||
}
|
||||
|
||||
class TakeEntity(
|
||||
var isCustom: Boolean, var id: Long
|
||||
)
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.app.IntentService
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import com.zhidao.roadcondition.util.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.lang.Exception
|
||||
|
||||
class DelayService : IntentService("DelayService") {
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "DelayService"
|
||||
|
||||
fun launchService(context: Context) {
|
||||
context.startService(Intent(context, DelayService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
override fun onStart(intent: Intent?, startId: Int) {
|
||||
super.onStart(intent, startId)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return super.onBind(intent)
|
||||
}
|
||||
|
||||
override fun setIntentRedelivery(enabled: Boolean) {
|
||||
super.setIntentRedelivery(enabled)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onHandleIntent(intent: Intent?) {
|
||||
Log.d(TAG, "start delay ----> ")
|
||||
|
||||
taskAsync(20_000) {
|
||||
try {
|
||||
Log.d(TAG, "delay finish, start Service")
|
||||
// MainService.launchService(this@DelayService, "0")
|
||||
|
||||
//删除一个原始视频(可能没删除的)文件夹下的所有文件(包括子目录内的文件)
|
||||
val file = File("/mnt/sdcard/DCIM/Camera/video/small/") //输入要删除文件目录的绝对路径
|
||||
deleteAllFile(file)
|
||||
|
||||
val compressFile = File("/mnt/sdcard/Movies/") //压缩过的视频
|
||||
deleteAllFile(compressFile)
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.util.Log
|
||||
import com.zhidao.roadcondition.model.InformationResource
|
||||
import com.zhidao.roadcondition.model.InformationType
|
||||
import com.zhidao.roadcondition.util.*
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-20
|
||||
*
|
||||
* 情报上报控制
|
||||
*/
|
||||
object InformationUploadController {
|
||||
|
||||
val TAG : String = this.javaClass.simpleName
|
||||
|
||||
private var mainServiceHttpModel = MainServiceController()
|
||||
|
||||
private val locker: Any = Any()
|
||||
|
||||
/**
|
||||
* 情报
|
||||
* Long -> 一个情报的id
|
||||
* InformationResource -> 一个情报的资源
|
||||
*/
|
||||
private val informationCache = mutableMapOf<Long, InformationResource>()
|
||||
|
||||
/**
|
||||
* 情报已上传到cos
|
||||
*/
|
||||
fun cosResourceReady(
|
||||
sourceType: Int,
|
||||
cosParameter: Map<String, String>,
|
||||
isCustomSend: Boolean,
|
||||
id: Long,
|
||||
callback: ((customSend: Boolean) -> Unit)
|
||||
) {
|
||||
Log.d(TAG, "cos resource ready. id=${id}")
|
||||
val ir = getInformationResourceById(id)
|
||||
ir?.let {
|
||||
it.isCosResourceReady = true
|
||||
it.sourceType = sourceType
|
||||
it.cosParameter = cosParameter
|
||||
it.isCustomSend = isCustomSend
|
||||
it.callback = callback
|
||||
tryUploadInformation(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInformationResourceById(id: Long): InformationResource? {
|
||||
if (!informationCache.containsKey(id)) {
|
||||
informationCache[id] = InformationResource(id)
|
||||
}
|
||||
return informationCache[id]
|
||||
}
|
||||
|
||||
/**
|
||||
* 已选择情报类型
|
||||
*/
|
||||
fun informationSelected(
|
||||
informationType: InformationType,
|
||||
newsType: String,
|
||||
operType: String,
|
||||
id: Long
|
||||
) {
|
||||
Log.d(TAG, "information type selected id=${id}, type=${informationType}")
|
||||
val ir = getInformationResourceById(id)
|
||||
ir?.let {
|
||||
it.isInformationSelected = true
|
||||
it.informationType = informationType
|
||||
it.newsType = newsType
|
||||
it.operType = operType
|
||||
tryUploadInformation(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryUploadInformation(ir: InformationResource?) {
|
||||
// synchronized(locker) {
|
||||
// ir?.let {
|
||||
// if (!it.isReady()) {
|
||||
// log(TAG, "source isn't ready.")
|
||||
// return@let
|
||||
// }
|
||||
// mainServiceHttpModel.sendInformationMessage(
|
||||
// it.sourceType,
|
||||
// it.cosParameter!!,
|
||||
// it.isCustomSend,
|
||||
// it.informationType?.dictValue!!,
|
||||
// isShare = true
|
||||
// ) { success ->
|
||||
// log(TAG, "上传成功!" + ir?.toString())
|
||||
// trackNormalEvent(
|
||||
// CarNet_user_upload,
|
||||
// mutableMapOf(
|
||||
// TRACK_KEY_TYPE to it.operType,
|
||||
// TRACK_KEY_NEWS_TYPE to it.newsType
|
||||
// )
|
||||
// )
|
||||
// if (it.isCustomSend) {
|
||||
// it.callback?.invoke(success)
|
||||
// }
|
||||
// informationCache.remove(it.id)
|
||||
// it.release()
|
||||
// recordUploadTime()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fun release(id: Long) {
|
||||
val target = informationCache.remove(id)
|
||||
target?.let {
|
||||
it.release()
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordUploadTime() {
|
||||
putLong("lastUploadTime", System.currentTimeMillis())
|
||||
}
|
||||
|
||||
fun isUpload2Frequently(): Boolean {
|
||||
val lastUploadTime = getLong("lastUploadTime", 0L)
|
||||
return System.currentTimeMillis() - lastUploadTime < 10_000L
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import com.elegant.analytics.Analytics
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.zhidao.cosupload.manager.CosUploadManagerImpl
|
||||
import com.zhidao.roadcondition.BuildConfig
|
||||
import com.zhidao.roadcondition.constant.*
|
||||
import com.zhidao.roadcondition.event.GetImageSuccessEvent
|
||||
import com.zhidao.roadcondition.event.LatLngStickyEventBus
|
||||
import com.zhidao.roadcondition.util.*
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.clearStrategyType
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyFrequency
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyInterval
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyType
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.Consumer
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
* 上报流程服务
|
||||
*/
|
||||
class MainService : Service() {
|
||||
|
||||
companion object {
|
||||
fun launchService(context: Context, params: UploadParams?) {
|
||||
val intent = Intent(context, MainService::class.java).apply {
|
||||
Log.e("MainService", "launchService type = $params")
|
||||
putExtra("params", params)
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var mainServiceHttpModel: MainServiceController
|
||||
private var mAlarmManager: AlarmManager =
|
||||
AbsMogoApplication.getApp().applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
|
||||
//是否已经获取过策略
|
||||
var isGetStrategies: Boolean = false
|
||||
val TAG: String = this.javaClass.simpleName
|
||||
|
||||
//1是一次性,2是周期性
|
||||
var picType: Int = 0
|
||||
var videoType: Int = 0
|
||||
var shareType: String = "type"
|
||||
var fromType: String = ""
|
||||
var isCustom: Boolean = false
|
||||
|
||||
var params: UploadParams? = null
|
||||
var mainInfoId: Long = 0
|
||||
|
||||
//发送主动上报结果广播给外部
|
||||
fun sendCustomResult(result: Boolean) {
|
||||
var intent = Intent(customResultAction)
|
||||
intent.putExtra("isSuccess", result)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.d(TAG, "onStartCommand -----------> ")
|
||||
//清理多媒体资源和sp策略数据
|
||||
clearStrategyType(this)
|
||||
//初始化埋点
|
||||
Analytics.getInstance().start(this)
|
||||
//参数说明:appKey: app唯一标识(比如:包名)
|
||||
CosUploadManagerImpl.getInstance(AbsMogoApplication.getApp().applicationContext)
|
||||
.init(BuildConfig.APPLICATION_ID, 2)
|
||||
//初始化语音
|
||||
VoiceController.initVoice()
|
||||
|
||||
if (intent != null) {
|
||||
params = intent.getParcelableExtra("params")
|
||||
params?.let {
|
||||
shareType = it.eventType
|
||||
fromType = it.fromType
|
||||
mainInfoId = 0 //TODO
|
||||
Log.d(TAG, "onStartCommand shareType = $shareType")
|
||||
if (shareType == TANLU_ROAD_CONGESTION || shareType == TANLU_TRAFFIC_CHECK || shareType == TANLU_ROAD_CLOSURE || shareType == TANLU_ROAD_CURRENT
|
||||
|| shareType == TANLU_ROAD_PONDING || shareType == TANLU_ROAD_ICING || shareType == TANLU_ROAD_HEAVY_FOG
|
||||
|| shareType == TANLU_ROAD_ACCIDENT || shareType == TANLU_ROAD_WORK
|
||||
) {
|
||||
// takePhoto(1, false, true)
|
||||
if (!fromType.equals(UPLOAD_FROM_STRATEGY_ACCIDENT_AUTO)) { // 是策略触发,不提示
|
||||
takeVideo(it.duration, isCustom = true, id = id)
|
||||
} else {
|
||||
takeVideo(it.duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "intent == null ")
|
||||
}
|
||||
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
//定时任务回调广播
|
||||
var mAlarmBroadCast: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(p0: Context?, p1: Intent) {
|
||||
Log.d(TAG, "receive alarm!!!!!!!!!!AlarmType===${p1.getIntExtra("AlarmType", 1)}")
|
||||
if (p1.action == alarmBroadAction) {
|
||||
if (p1.getIntExtra("AlarmType", 1) == AlarmTypePic) {
|
||||
//拍照
|
||||
var number = p1.getLongExtra("number", 1)
|
||||
takePhoto(number, true)
|
||||
} else {
|
||||
//录像
|
||||
var duration = p1.getIntExtra("duration", 3)
|
||||
takeVideo(duration, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//主动上报图片情报广播
|
||||
var mCustomSendBroadCast: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(p0: Context?, p1: Intent) {
|
||||
val id = p1.getLongExtra("id", 0L)
|
||||
if (p1.action == sendInformationAction) {
|
||||
takeVideo(10, isCustom = true, id = id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
init()
|
||||
//初始化定位
|
||||
LocationUtil.getInstance().initLocation()
|
||||
|
||||
initLocationListener()
|
||||
loadConfigurations()
|
||||
LatLngStickyEventBus.getInstance().register(this)
|
||||
trackNormalEvent(CarNet_MainService_Start, null)
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
//初始化拍照sdk
|
||||
CarCorderController.initCarCorderController()
|
||||
mainServiceHttpModel = MainServiceController()
|
||||
registReceiver()
|
||||
// CosStatusController().registerCos(this)
|
||||
CosCallbackMapController.init(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载各种配置
|
||||
*/
|
||||
private fun loadConfigurations() {
|
||||
// mainServiceHttpModel.getAuthorization()
|
||||
// mainServiceHttpModel.getNeedAuth { authStatus ->
|
||||
// // isNeedAuth = authStatus
|
||||
// }
|
||||
// mainServiceHttpModel.getSplashConfig()
|
||||
}
|
||||
|
||||
var id: Long = System.currentTimeMillis()
|
||||
|
||||
/**
|
||||
* 获取图片成功
|
||||
*/
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 98)
|
||||
fun getImageEvent(getImageSuccessEvent: GetImageSuccessEvent) {
|
||||
var info = LocationUtil.getInstance().getLocationInfo()
|
||||
Log.e("MainService", "getImageEvent long = ${info.longitude} ----> lat= ${info.latitude}")
|
||||
Log.d(
|
||||
"MainService",
|
||||
"getImageEvent url = " + getImageSuccessEvent.getImageUrl() + ">>>>type =" + getImageSuccessEvent.getType()
|
||||
)
|
||||
sendMarkerInfoReceiver(
|
||||
info.latitude,
|
||||
info.longitude,
|
||||
getImageSuccessEvent.getImageUrl(),
|
||||
getImageSuccessEvent.getType()
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendMarkerInfoReceiver(lat: Double, lon: Double, imageUrl: String?, type: String?) {
|
||||
Log.e("MainService", "sendMarkerInfoReceiver ------> type = $type ")
|
||||
Log.e("MainService", "sendMarkerInfoReceiver ------> fromType = $fromType ")
|
||||
Log.e("MainService", "sendMarkerInfoReceiver ------> isCustom = $isCustom ")
|
||||
var intent = Intent()
|
||||
intent.action = "com.zhidao.roadcondition.marker.info"
|
||||
intent.putExtra("type", type)
|
||||
intent.putExtra("imageUrl", imageUrl)
|
||||
intent.putExtra("lat", lat)
|
||||
intent.putExtra("lon", lon)
|
||||
intent.putExtra("custom", isCustom)
|
||||
intent.putExtra("fromType", fromType)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化定位监听
|
||||
*/
|
||||
private fun initLocationListener() {
|
||||
//开始开始监听速度,只要超过一次5公里每小时则即开始获取策略进行本地上报 只有release才加此判断,qa环境方便测试
|
||||
LocationUtil.getInstance().setonSpeedlistenner(object : LocationUtil.SpeedListener {
|
||||
override fun onSpeedGet(speed: Float) {
|
||||
if (speed > (5 / 3.6f) && !isGetStrategies) {
|
||||
mainServiceHttpModel.initStrategies {
|
||||
handleReportStrategy()
|
||||
}
|
||||
Log.d("MainService", "initLocationListener more than 5 start upload speed = $speed")
|
||||
isGetStrategies = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报策略判断
|
||||
*/
|
||||
private fun handleReportStrategy() {
|
||||
//1是一次性,2是周期性
|
||||
picType = getStrategyFrequency(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"pic",
|
||||
getStrategyType("pic")
|
||||
)
|
||||
videoType = getStrategyFrequency(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"video",
|
||||
getStrategyType("video")
|
||||
)
|
||||
Log.d("MainService", "handleReportStrategy picType = $picType ---videoType = $videoType")
|
||||
if (picType == 1) {
|
||||
takePhoto(1)
|
||||
} else if (picType == 2) {
|
||||
postPhotoAlarmTask(true)
|
||||
}
|
||||
|
||||
if (videoType == 1) {
|
||||
takeVideo(10)
|
||||
} else if (videoType == 2) {
|
||||
postVideoAlarmTask(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registReceiver() {
|
||||
//注册定时任务回调
|
||||
val intentFilter = IntentFilter(alarmBroadAction)
|
||||
intentFilter.addAction("com.zhidao.sendmessage.test")
|
||||
intentFilter.addAction("com.zhidao.takevideo.test")
|
||||
intentFilter.addAction("com.zhidao.takepic.test")
|
||||
registerReceiver(mAlarmBroadCast, intentFilter)
|
||||
//注册主动上报广播
|
||||
// var customSendIntentFilter = IntentFilter(sendInformationAction)
|
||||
// registerReceiver(mCustomSendBroadCast, customSendIntentFilter)
|
||||
}
|
||||
|
||||
//获取图片
|
||||
private fun takePhoto(picNum: Long, isInterval: Boolean = false, isCustom: Boolean = false) {
|
||||
Log.d("MainService", "takePhoto -----1----->")
|
||||
//判断是否授权
|
||||
// if (isAuthorization(BaseApplication.getAppContext())) {
|
||||
// log(TAG, "takePhoto -----2----->")
|
||||
//目前不支持连拍,只能定时2秒拍一张 第一期每次只拍一张
|
||||
Observable.intervalRange(0, 1, 0, 2_000, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(Consumer {
|
||||
CarCorderController.takePhoto(1, 1, false, isCustom, TANLU_ROAD_CURRENT, mainInfoId, fromType)
|
||||
})
|
||||
// }
|
||||
|
||||
postPhotoAlarmTask(isInterval)
|
||||
|
||||
this@MainService.isCustom = isCustom
|
||||
}
|
||||
|
||||
//获取录像
|
||||
private fun takeVideo(
|
||||
duration: Int,
|
||||
isInterval: Boolean = false,
|
||||
isCustom: Boolean = false,
|
||||
id: Long = 0
|
||||
) {
|
||||
Log.d("MainService", "takeVideo --------1---->")
|
||||
// if (isAuthorization(BaseApplication.getAppContext())) {
|
||||
// log(TAG, "takeVideo --------2---->")
|
||||
CarCorderController.takeVideo(1, duration, isCustom, id, if (isCustom) shareType else TANLU_ROAD_CURRENT, mainInfoId, fromType)
|
||||
// }
|
||||
postVideoAlarmTask(isInterval)
|
||||
|
||||
this@MainService.isCustom = isCustom
|
||||
}
|
||||
|
||||
private fun postPhotoAlarmTask(isInterval: Boolean = false) {
|
||||
if (isInterval) {
|
||||
trackNormalEvent(CarNet_Create_Task, null)
|
||||
val intent = Intent()
|
||||
intent.action = alarmBroadAction
|
||||
intent.putExtra("number", getLong(PIC_NUMBER, PIC_NUMBER_DEFAULT))
|
||||
intent.putExtra("AlarmType", AlarmTypePic)
|
||||
var pendingIntent = PendingIntent.getBroadcast(this, AlarmTypePic, intent, 0)
|
||||
Log.d(
|
||||
"MainService",
|
||||
"postPhotoAlarmTask time =" + getStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"pic",
|
||||
getStrategyType("pic")
|
||||
)
|
||||
)
|
||||
|
||||
mAlarmManager.setExact(
|
||||
AlarmManager.RTC, System.currentTimeMillis() +
|
||||
getStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"pic",
|
||||
getStrategyType("pic")
|
||||
)
|
||||
, pendingIntent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//开始倒计时任务
|
||||
private fun postVideoAlarmTask(isInterval: Boolean = false) {
|
||||
if (isInterval) {
|
||||
trackNormalEvent(CarNet_Create_Task, null)
|
||||
val videoIntent = Intent()
|
||||
videoIntent.action = alarmBroadAction
|
||||
videoIntent.putExtra(
|
||||
"duration", (VIDEO_DURATION_DEFAULT / 1000).toInt()
|
||||
)
|
||||
videoIntent.putExtra("AlarmType", AlarmTypeVideo)
|
||||
var videoPendingIntent =
|
||||
PendingIntent.getBroadcast(this, AlarmTypeVideo, videoIntent, 0)
|
||||
Log.d(
|
||||
"MainService",
|
||||
"postVideoAlarmTask time =" + getStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"video",
|
||||
getStrategyType("video")
|
||||
)
|
||||
)
|
||||
|
||||
mAlarmManager.setExact(
|
||||
AlarmManager.RTC, System.currentTimeMillis() +
|
||||
getStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
"video",
|
||||
getStrategyType("video")
|
||||
)
|
||||
, videoPendingIntent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unregisterReceiver(mAlarmBroadCast)
|
||||
unregisterReceiver(mCustomSendBroadCast)
|
||||
CarCorderController.release()
|
||||
CosCallbackMapController.release()
|
||||
LatLngStickyEventBus.getInstance().unregister(this)
|
||||
LatLngStickyEventBus.getInstance().removeAllStickyEvents()
|
||||
trackNormalEvent(CarNet_MainService_Destory, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.util.Log
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.roadcondition.model.*
|
||||
import com.zhidao.roadcondition.net.request
|
||||
import com.zhidao.roadcondition.util.*
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyFrequency
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyInterval
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyMaxSpeed
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyMinSpeed
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyType
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.setStrategyValidity
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class MainServiceController {
|
||||
|
||||
companion object {
|
||||
var TAG = this.javaClass.name
|
||||
}
|
||||
|
||||
//逆地理编码是否重试
|
||||
private var geoRetryed = false
|
||||
|
||||
private val strategyeModel by lazy { StrategyServiceModel() }
|
||||
|
||||
fun initStrategies(initFinish: (() -> Unit)? = null) {
|
||||
request<BaseResponse<Results>> {
|
||||
loader {
|
||||
strategyeModel.getCityStrategy()
|
||||
}
|
||||
onSuccess {
|
||||
it.result.let { strategy ->
|
||||
trackNormalEvent(CarNet_Get_Strategy, null)
|
||||
Log.d(TAG, "pic =" + strategy.cityStrategy.pic)
|
||||
Log.d(TAG, "video =" + strategy.cityStrategy.video)
|
||||
syncStrategiesData(strategy.cityStrategy)
|
||||
initFinish?.invoke()
|
||||
}
|
||||
}
|
||||
onError {
|
||||
reInitStrategies()
|
||||
Log.e(TAG, "initStrategies onError ${it.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reInitStrategies() = runBlocking {
|
||||
launch {
|
||||
// delay(30_000)
|
||||
initStrategies()
|
||||
}
|
||||
}
|
||||
|
||||
//将数据同步到sharePreference中
|
||||
fun syncStrategiesData(strategy: CityStrategy) {
|
||||
if (strategy?.pic != null && strategy.video!=null) {
|
||||
setStrategyType(AbsMogoApplication.getApp().applicationContext, strategy.pic.strategyType, "pic")
|
||||
setStrategyType(AbsMogoApplication.getApp().applicationContext, strategy.video.strategyType, "video")
|
||||
setStrategyFrequency(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.pic.strategyType,
|
||||
"pic",
|
||||
strategy.pic.reportType
|
||||
)
|
||||
setStrategyFrequency(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.video.strategyType,
|
||||
"video",
|
||||
strategy.video.reportType
|
||||
)
|
||||
setStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.pic.strategyType,
|
||||
"pic",
|
||||
strategy.pic.reportTimeInterval * 60 * 1000L
|
||||
)
|
||||
setStrategyInterval(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.video.strategyType,
|
||||
"video",
|
||||
strategy.video.reportTimeInterval * 60 * 1000L
|
||||
)
|
||||
setStrategyValidity(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.pic.strategyType,
|
||||
"pic",
|
||||
strategy.pic.infoTimeout
|
||||
)
|
||||
setStrategyValidity(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.video.strategyType,
|
||||
"video",
|
||||
strategy.video.infoTimeout
|
||||
)
|
||||
setStrategyMaxSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.pic.strategyType,
|
||||
"pic",
|
||||
strategy.pic.getMaxSpeed()
|
||||
)
|
||||
setStrategyMaxSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.video.strategyType,
|
||||
"video",
|
||||
strategy.video.getMaxSpeed()
|
||||
)
|
||||
setStrategyMinSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.pic.strategyType,
|
||||
"pic",
|
||||
strategy.pic.minSpeed
|
||||
)
|
||||
setStrategyMinSpeed(
|
||||
AbsMogoApplication.getApp().applicationContext,
|
||||
strategy.video.strategyType,
|
||||
"video",
|
||||
strategy.video.minSpeed
|
||||
)
|
||||
} else {
|
||||
Log.d(TAG, "strategy Data is null")
|
||||
}
|
||||
}
|
||||
|
||||
// fun getAuthorization() {
|
||||
// request<BaseResponse<Any>> {
|
||||
// loader {
|
||||
// strategyeModel.getAuthorization()
|
||||
// }
|
||||
// onSuccess {
|
||||
// it.let {
|
||||
// var jsonObject = JSONObject(it.result.toString())
|
||||
// setAuthorization(
|
||||
// AbsMogoApplication.getApp().applicationContext,
|
||||
// jsonObject.getBoolean("enable")
|
||||
// )
|
||||
// Log.d("MainServiceController", "MainServiceController getAuthorization onSuccess enable=" + jsonObject.getBoolean("enable"))
|
||||
// }
|
||||
// }
|
||||
// onError {
|
||||
// Log.d("MainServiceController", "getAuthorization error")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fun getNeedAuth(authStatus: ((Boolean) -> Unit)? = null) {
|
||||
// request<BaseResponse<CommonConfig>> {
|
||||
// loader {
|
||||
// strategyeModel.getAllConfig()
|
||||
// }
|
||||
// onSuccess {
|
||||
// it.let {
|
||||
// var config = it.result
|
||||
// config.auth?.let { auth ->
|
||||
// authStatus?.invoke(auth.isNeedAuth == 1)
|
||||
// }
|
||||
// if (config.isActiveNonNull()) {
|
||||
// //保存运营活动webUrl、imgUrl SP
|
||||
// setActiveWebUrl(config.active.webUrl)
|
||||
// setActiveImgUrl(config.active.imageUrl)
|
||||
// setActiveStatus(config.active.status)
|
||||
// } else {
|
||||
// //清除运营活动配置SP
|
||||
// clearActiveInfo()
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// onError {
|
||||
// Log.d("MainServiceController", "getAuthorization error")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //获取加载页面配置
|
||||
// getSplashConfig()
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 获取加载页面配置
|
||||
*/
|
||||
// fun getSplashConfig() {
|
||||
// request<BaseResponse<SplashConfig>> {
|
||||
// loader {
|
||||
// strategyeModel.getSplashConfig()
|
||||
// }
|
||||
// onSuccess {
|
||||
// it.let {
|
||||
// var splashConfig = it.result
|
||||
// val timeFlag = getLong(TIME_QUANTUM, 0)
|
||||
// if (splashConfig != null && !TextUtils.isEmpty(splashConfig.image)) {
|
||||
// //保存倒计时时间
|
||||
// Log.d(TAG, "splashConfig.displayTime =" + splashConfig.displayTime)
|
||||
// putInt(COUNT_DOWN_TIME, splashConfig.displayTime)
|
||||
// //保存语音播报
|
||||
// putCommonString(VOICE_TEXT, splashConfig.content)
|
||||
// //下载图片
|
||||
// if (!TextUtils.isEmpty(splashConfig.image)) {
|
||||
// Log.d(TAG, "splashConfig.effectiveFlag =" + splashConfig.effectiveFlag + "-->timeFlag=" + timeFlag)
|
||||
// if (timeFlag != splashConfig.effectiveFlag) {
|
||||
// ImageFactory.downloadPic(splashConfig.image)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //保存时间戳
|
||||
// putLong(TIME_QUANTUM, splashConfig.effectiveFlag)
|
||||
// } else {
|
||||
// putCommonString(VOICE_TEXT, "")
|
||||
// putInt(COUNT_DOWN_TIME, 0)
|
||||
// putCommonBoolean(IS_SAVE_SPLASH, false)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// onError {
|
||||
// Log.d(TAG, "getSplashConfig error it.printStackTrace()=" + it.printStackTrace())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//上传情报数据
|
||||
fun sendInformationMessage(
|
||||
type: Int,
|
||||
url: Map<String, String>,
|
||||
isCustom: Boolean = false,
|
||||
trafficInfoType:String = "",
|
||||
isShare:Boolean = false,
|
||||
poiType:String,
|
||||
mainInfoId:Long,
|
||||
customSend: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
Log.d(TAG, " sendInformationMessage poiType = $poiType");
|
||||
//删除测试数据
|
||||
var locationInfo = LocationUtil.getInstance().getLocationInfo();
|
||||
if (locationInfo.address.isNullOrEmpty()) {
|
||||
geoLocation(type, url, locationInfo, isCustom,trafficInfoType, isShare, customSend,poiType,mainInfoId)
|
||||
} else {
|
||||
postInformationMessage(
|
||||
getInformationBody(type, url, locationInfo, isCustom, trafficInfoType, isShare,poiType,mainInfoId),
|
||||
customSend
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//如果address为空则逆地理编码
|
||||
private fun geoLocation(
|
||||
type: Int,
|
||||
url: Map<String, String>,
|
||||
locationInfo: LocationInfo,
|
||||
isCustom: Boolean,
|
||||
trafficInfoType:String,
|
||||
isShare: Boolean,
|
||||
customSend: ((Boolean) -> Unit)? = null,
|
||||
poiType: String,
|
||||
mainInfoId: Long
|
||||
) {
|
||||
Log.d(TAG, " geoLocation -- poiType = $poiType");
|
||||
LocationUtil.getInstance()
|
||||
.geoCodeLocation(locationInfo.toLatLngPoint(), { locInfo: LocationInfo ->
|
||||
postInformationMessage(
|
||||
getInformationBody(type, url, locationInfo, isCustom, trafficInfoType, isShare, poiType,mainInfoId),
|
||||
customSend
|
||||
)
|
||||
}, {
|
||||
//转换失败的情况下再重试一次
|
||||
geoRetryed = if (!geoRetryed) {
|
||||
geoLocation(type, url, locationInfo, isCustom, trafficInfoType, isShare, customSend, poiType,mainInfoId)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private fun postInformationMessage(
|
||||
informationBody: InformationBody,
|
||||
customSend: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
trackUploadServer(3)
|
||||
request<BaseResponse<Any>> {
|
||||
loader {
|
||||
strategyeModel.uploadInformation(informationBody)
|
||||
}
|
||||
onSuccess {
|
||||
Log.i(TAG, "upload message success ")
|
||||
trackUploadServer(1)
|
||||
// CosStatusController().videoAndThumbMap.clear()
|
||||
customSend?.invoke(true)
|
||||
|
||||
}
|
||||
onError {
|
||||
Log.i(TAG, "$it upload message ${it.message}")
|
||||
trackUploadServer(2)
|
||||
// CosStatusController().videoAndThumbMap.clear()
|
||||
customSend?.invoke(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//上传服务器
|
||||
private fun trackUploadServer(type: Int) {
|
||||
trackNormalEvent(
|
||||
CarNet_Servers_Upload, mutableMapOf("type" to type)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
val AlarmTypePic: Int = 1 //定时任务类型 1照片
|
||||
val AlarmTypeVideo: Int = 2 //定时任务类型 2视频
|
||||
|
||||
val alarmBroadAction: String = "com.zhidao.roadCondition.AlarmBroadCast" //定时广播
|
||||
val sendInformationAction: String = "com.zhidao.roadCondition.SendInformation" //主动上报广播
|
||||
val customResultAction: String = "com.zhidao.roadCondition.CustomResult" //主动上报结果广播
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import com.zhidao.auto.carcorder.callback.TakePhotoCallback
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-11-19
|
||||
*
|
||||
* 拍照拦截器
|
||||
*/
|
||||
interface TakePhotoInterceptor : TakePhotoCallback {
|
||||
|
||||
fun intercept(): Boolean
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class UploadParams(val eventType:String,val fromType:String,val duration:Int) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readString()!!,
|
||||
parcel.readString()!!,
|
||||
parcel.readInt())
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(eventType)
|
||||
parcel.writeString(fromType)
|
||||
parcel.writeInt(duration)
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "UploadParams(eventType='$eventType', fromType='$fromType', duration=$duration)"
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<UploadParams> {
|
||||
override fun createFromParcel(parcel: Parcel): UploadParams {
|
||||
return UploadParams(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<UploadParams?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.zhidao.roadcondition.service
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.auto.platform.voice.VoiceClient
|
||||
|
||||
/**
|
||||
* @description 声音控制类
|
||||
*
|
||||
* @author lixiaopeng
|
||||
* @since 2019-11-01
|
||||
*/
|
||||
object VoiceController {
|
||||
private lateinit var voiceClient: VoiceClient
|
||||
|
||||
fun initVoice() {
|
||||
voiceClient = VoiceClient(AbsMogoApplication.getApp().applicationContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语音命令回调接口
|
||||
* @param callBack
|
||||
*/
|
||||
fun setCallBack(callBack: VoiceClient.VoiceCmdCallBack) {
|
||||
voiceClient.setCallBack(callBack)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param speakText 语音播报内容
|
||||
*/
|
||||
fun speakVoice(speakText: String) {
|
||||
voiceClient.speakDefault(speakText)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册免唤醒命令
|
||||
* @param customType 命令
|
||||
* @param customWakeupCmd 命令对应的唤醒词集合
|
||||
*/
|
||||
fun registerCustomWakeupCmd(customType: String, customWakeupCmd: Array<String>) {
|
||||
voiceClient.registerCustomWakeupCmd(customType, customWakeupCmd)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消免唤醒命令
|
||||
* @param customType 命令
|
||||
*/
|
||||
fun unRegisterCustomWakeupCmd(customType: String) {
|
||||
voiceClient.unRegisterCustomWakeupCmd(customType)
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源(界面销毁的时候调用)
|
||||
*/
|
||||
fun release() {
|
||||
voiceClient.release()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.content.Context
|
||||
import com.elegant.analytics.Analytics
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.network.Utils
|
||||
import com.zhidao.roadcondition.aspect.DebugLog
|
||||
import java.util.HashMap
|
||||
|
||||
const val CarNet_Alive:String = "CarNet_Alive"//探路日活DAU埋点
|
||||
const val CarNet_Scheme_Channel:String = "CarNet_Scheme_Channel"//探路Scheme渠道区分
|
||||
const val APPENTER_FRONT:String = "appenterfront"//探路Scheme渠道区分
|
||||
|
||||
const val CarNet_auto_upload:String = "CarNet_auto_upload"//情报自动上传时间(自动上报图片)
|
||||
const val CarNet_click:String ="CarNet_click"//用户点击查看大图
|
||||
const val CarNet_right_handle:String ="CarNet_right_handle"//用户切换情报-地图切换
|
||||
const val CarNet_event_number:String ="CarNet_event_number" //用户获取的信息数量
|
||||
const val CarNet_user_upload:String ="CarNet_user_upload" //用户主动上报视频type=1 手动点击 type=2 语音
|
||||
const val CarNet_auto_upload_video:String ="CarNet_auto_upload_video"//自动上报视频
|
||||
const val CarNet_click_search:String = "CarNet_click_search" //点击地图搜索
|
||||
const val CarNet_user_get:String = "CarNet_user_get"//用户查看情报(首页视频/图片,开始播放即算做用户查看)type=1 视频 type=2 图片
|
||||
const val CarNet_road_search:String = "CarNet_road_search"//有导航路线时的沿途查询
|
||||
|
||||
const val CarNet_MainService:String = "CarNet_MainService" //开机
|
||||
const val CarNet_MainService_Start:String ="CarNet_MainService_Start" //服务开启
|
||||
const val CarNet_MainService_Destory:String ="CarNet_MainService_Destory" //服务销毁
|
||||
const val CarNet_Get_Strategy:String = "CarNet_Get_Strategy" //策略拉取成功
|
||||
const val CarNet_Create_Task:String = "CarNet_Create_Task" //创建定时任务
|
||||
const val CarNet_Get_Picture:String = "CarNet_Get_Picture" //获取图片,type=1 调用, type=2 成功, type=3 失败
|
||||
const val CarNet_Get_Video:String = "CarNet_Get_Video" //获取视频,type=1 调用,type=2 成功,type=3 失败
|
||||
const val CarNet_Cos_Upload:String = "CarNet_Cos_Upload" //上传COS, type=1 成功, type=2 失败, type=3 开始
|
||||
const val CarNet_Servers_Upload:String = "CarNet_Servers_Upload" //上传服务端, type=1 成功,type=2 失败, type=3 开始
|
||||
const val CarNet_Voice_Search:String = "CarNet_Voice_Search" //语音搜索路况,type=1 成功,type=2 失败
|
||||
const val CarNet_USER_SHOW:String = "CarNet_user_show" //情报展示时长,showtime 加载列表时长
|
||||
const val CarNet_USER_LOAD:String = "CarNet_user_load" //情报加载时长,type=1 视频,2图片
|
||||
|
||||
const val CarNet_live_broadcast = "CarNet_live_broadcast" // 地图页面点击直播(在线可直播车机)
|
||||
//自定义埋点
|
||||
@DebugLog
|
||||
fun trackNormalEvent(event: String, data: MutableMap<String, Any>?, context: Context = AbsMogoApplication.getApp().applicationContext) {
|
||||
var data = data
|
||||
if (data == null) {
|
||||
data = HashMap()
|
||||
}
|
||||
val localParams = HashMap<String, Any>()
|
||||
//公共参数 time sn
|
||||
localParams["time"] = System.currentTimeMillis()
|
||||
localParams["systemversion"] = getSystemVersion(context)
|
||||
localParams["sn"] = Utils.getSn()
|
||||
|
||||
// Log.d("liyz", "data =" + data.toString() + ">>>>event=" + event)
|
||||
Analytics.getInstance().setCustomParams(localParams)
|
||||
Analytics.getInstance().track(event, data)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
@file:JvmName("DeviceInfo")
|
||||
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.content.Context
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
private const val SN_INFO: String = "gsm.serial"
|
||||
|
||||
fun getSn(): String {
|
||||
var serial = ""
|
||||
try {
|
||||
var cls = Class.forName("android.os.SystemProperties")
|
||||
var method = cls.getMethod("get", String::class.java)
|
||||
serial = method.invoke(cls, SN_INFO) as String
|
||||
} catch (var4: ClassNotFoundException) {
|
||||
var4.printStackTrace()
|
||||
} catch (var5: NoSuchMethodException) {
|
||||
var5.printStackTrace()
|
||||
} catch (var6: InvocationTargetException) {
|
||||
var6.printStackTrace()
|
||||
} catch (var7: IllegalAccessException) {
|
||||
var7.printStackTrace()
|
||||
}
|
||||
return serial
|
||||
}
|
||||
|
||||
fun getSystemVersion(context: Context): String {
|
||||
try {
|
||||
var cls = context.classLoader
|
||||
var systemProperties = cls.loadClass("android.os.SystemProperties")
|
||||
var paramTypes = String::class.java
|
||||
val get = systemProperties.getMethod("get", paramTypes)
|
||||
val version = get.invoke(systemProperties, *arrayOf<Any>("ro.fota.version")) as String
|
||||
return if (!version.trim().isNullOrEmpty()) version.trim() else ""
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import java.io.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
//创建文件上传请求体
|
||||
fun fileToMultiPart(fileUrl: String): MultipartBody.Part? {
|
||||
var file = File(fileUrl)
|
||||
if (file.exists()) {
|
||||
var requestBody = RequestBody.create(MediaType.parse("image/jpg"), file)
|
||||
return MultipartBody.Part.createFormData("file", file.name, requestBody)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun deletePicFile(filePath: String?): Boolean {
|
||||
var file = File(filePath)
|
||||
if (file.exists()) {
|
||||
//如果图片地址包含此路径则是C上面的拍照,需要再删除后摄图片
|
||||
if (filePath!!.contains("usbotg-1-1.1")) {
|
||||
//将地址替换成后摄图片地址
|
||||
var backFile =
|
||||
File(filePath.replace("frontPic", "backPic").replace("PhotoFront", "PhotoBack"))
|
||||
if (backFile.exists()) {
|
||||
return backFile.delete()
|
||||
}
|
||||
return file.delete()
|
||||
} else
|
||||
return file.delete()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//删除某个目录下所有文件
|
||||
fun deleteAllFile(file: File?) { //判断文件不为null或文件目录存在
|
||||
if (file == null || !file.exists()) {
|
||||
Log.e("liyz", "文件删除失败,请检查文件路径是否正确")
|
||||
return
|
||||
}
|
||||
//取得这个目录下的所有子文件对象
|
||||
val files: Array<File> = file.listFiles()
|
||||
//遍历该目录下的文件对象
|
||||
for (f in files) {
|
||||
val name: String = file.getName()
|
||||
Log.e("liyz", name)
|
||||
//判断子目录是否存在子目录,如果是文件则删除
|
||||
if (f.isDirectory()) {
|
||||
deleteAllFile(f)
|
||||
} else {
|
||||
f.delete()
|
||||
}
|
||||
}
|
||||
//删除空文件夹 for循环已经把上一层节点的目录清空。
|
||||
// file.delete()
|
||||
}
|
||||
|
||||
|
||||
//根据本地视频文件生成缩略图文件
|
||||
fun getVideoThumbnail(filePath: String, picPath: String): Boolean {
|
||||
var b: Bitmap? = null
|
||||
var retriever = MediaMetadataRetriever()
|
||||
try {
|
||||
retriever.setDataSource(filePath)
|
||||
b = retriever.getFrameAtTime(0)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: RuntimeException) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
try {
|
||||
retriever.release()
|
||||
} catch (e: RuntimeException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return bitmapToFile(b, picPath)
|
||||
}
|
||||
|
||||
//bitmap转为file
|
||||
fun bitmapToFile(bitmap: Bitmap?, filePath: String): Boolean {
|
||||
val baos = ByteArrayOutputStream()
|
||||
bitmap?.compress(Bitmap.CompressFormat.JPEG, 50, baos)
|
||||
val file = File(filePath)
|
||||
try {
|
||||
if (file.exists())
|
||||
file.delete()
|
||||
file.createNewFile()
|
||||
val fos = FileOutputStream(file)
|
||||
var ins = ByteArrayInputStream(baos.toByteArray())
|
||||
var x = 0
|
||||
val b = ByteArray(1024 * 100)
|
||||
while ({ x = ins.read(b);x }() != -1) {
|
||||
fos.write(b, 0, x)
|
||||
}
|
||||
fos.close()
|
||||
bitmap?.recycle()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
//获取压缩后的视频路径
|
||||
fun getCompressVideoPath(): String {
|
||||
val moviesDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_MOVIES
|
||||
)
|
||||
moviesDir.mkdirs()
|
||||
|
||||
val builder = StringBuilder()
|
||||
builder.append("compress_video_")
|
||||
.append(SimpleDateFormat("yyyyMMddHHmmss").format(Date()))
|
||||
val filePrefix = builder.toString()
|
||||
val fileExtn = ".mp4"
|
||||
var destPath = File(moviesDir, filePrefix + fileExtn)
|
||||
|
||||
var fileNo = 0
|
||||
while (destPath.exists()) {
|
||||
fileNo++
|
||||
destPath = File(moviesDir, filePrefix + fileNo + fileExtn)
|
||||
}
|
||||
|
||||
return destPath.absolutePath
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存图片到本地
|
||||
*/
|
||||
fun saveImageToSdcard(bmp: Bitmap): Boolean {
|
||||
var currentFile: File
|
||||
lateinit var fos: FileOutputStream
|
||||
|
||||
var picFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
|
||||
picFile.mkdirs()
|
||||
|
||||
val builder = StringBuilder()
|
||||
builder.append("splash_bg")
|
||||
val filePrefix = builder.toString()
|
||||
val fileOut = ".jpg"
|
||||
currentFile = File(picFile, filePrefix + fileOut)
|
||||
|
||||
try {
|
||||
fos = FileOutputStream(currentFile)
|
||||
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos)
|
||||
fos.flush()
|
||||
} catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
fos.close()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取本地保存的图片地址
|
||||
*/
|
||||
fun getImagePath(): String {
|
||||
return "/mnt/sdcard/Pictures/splash_bg.jpg"
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.util.Log
|
||||
import com.amap.api.location.AMapLocation
|
||||
import com.amap.api.location.AMapLocationClient
|
||||
import com.amap.api.location.AMapLocationClientOption
|
||||
import com.amap.api.location.AMapLocationListener
|
||||
import com.amap.api.services.core.LatLonPoint
|
||||
import com.amap.api.services.geocoder.*
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.roadcondition.model.LocationInfo
|
||||
|
||||
|
||||
private fun RegeocodeAddress.toLocInfo(
|
||||
address: RegeocodeAddress,
|
||||
latlngPoint: LatLonPoint
|
||||
): LocationInfo {
|
||||
return LocationInfo(
|
||||
address.province,
|
||||
address.city,
|
||||
address.cityCode,
|
||||
address.district,
|
||||
address.adCode,
|
||||
address.roads[0].name,
|
||||
latlngPoint.longitude,
|
||||
latlngPoint.latitude,
|
||||
address.formatAddress,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
private fun AMapLocation.toLocInfo(location: AMapLocation): LocationInfo {
|
||||
return LocationInfo(
|
||||
location.province,
|
||||
location.city,
|
||||
location.cityCode,
|
||||
location.district,
|
||||
location.adCode,
|
||||
location.street,
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
location.address,
|
||||
location.time,
|
||||
location.bearing
|
||||
)
|
||||
}
|
||||
|
||||
class LocationUtil private constructor() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "LocationUtil"
|
||||
private var instance: LocationUtil? = null
|
||||
|
||||
@Synchronized
|
||||
fun getInstance(): LocationUtil {
|
||||
if (instance == null) {
|
||||
instance = LocationUtil()
|
||||
}
|
||||
return instance!!
|
||||
}
|
||||
}
|
||||
|
||||
interface OnMapLocationChangedListener {
|
||||
fun onChanged(locationInfo: LocationInfo)
|
||||
}
|
||||
|
||||
private var listener: OnMapLocationChangedListener? = null
|
||||
|
||||
private var init: Boolean = false
|
||||
private var mContext = AbsMogoApplication.getApp().applicationContext
|
||||
private var locationClient: AMapLocationClient? = null
|
||||
private var locationOption: AMapLocationClientOption? = null
|
||||
private var speedListener: SpeedListener? = null
|
||||
private var locationInfo: LocationInfo = LocationInfo()
|
||||
private var speed: Float = 0.0f
|
||||
|
||||
fun initLocation() {
|
||||
//初始化client
|
||||
locationOption = getDefaultOption()
|
||||
locationClient = AMapLocationClient(mContext)
|
||||
//设置定位参数
|
||||
locationClient!!.setLocationOption(locationOption)
|
||||
// 设置定位监听
|
||||
locationClient!!.setLocationListener(locationListener)
|
||||
init = true
|
||||
startLocation()
|
||||
}
|
||||
|
||||
private fun getDefaultOption(): AMapLocationClientOption {
|
||||
val mOption = AMapLocationClientOption()
|
||||
mOption.locationMode =
|
||||
AMapLocationClientOption.AMapLocationMode.Hight_Accuracy//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
|
||||
mOption.isGpsFirst = true//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
|
||||
mOption.httpTimeOut = 30000//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
|
||||
mOption.interval = 5000//可选,设置定位间隔。默认为2秒
|
||||
mOption.isNeedAddress = true//可选,设置是否返回逆地理地址信息。默认是true
|
||||
mOption.isOnceLocation = false//可选,设置是否单次定位。默认是false
|
||||
mOption.isOnceLocationLatest = false//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
|
||||
AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP)//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
|
||||
mOption.isSensorEnable = true//可选,设置是否使用传感器。默认是false
|
||||
mOption.isWifiScan =
|
||||
true //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
|
||||
mOption.isLocationCacheEnable = false //可选,设置是否使用缓存定位,默认为true
|
||||
mOption.geoLanguage =
|
||||
AMapLocationClientOption.GeoLanguage.DEFAULT//可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
|
||||
return mOption
|
||||
}
|
||||
|
||||
private fun startLocation() {
|
||||
if (checkInit()) {
|
||||
// 设置定位参数
|
||||
locationClient!!.setLocationOption(locationOption)
|
||||
// 启动定位
|
||||
locationClient!!.startLocation()
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnMapLocationChangedListener(listener: OnMapLocationChangedListener) {
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 定位监听
|
||||
*/
|
||||
private var locationListener: AMapLocationListener = AMapLocationListener { location ->
|
||||
if (null != location) {
|
||||
locationInfo.longitude = location.longitude
|
||||
locationInfo.latitude = location.latitude
|
||||
locationInfo.address = location.address
|
||||
locationInfo.time = location.time
|
||||
locationInfo.provinceName = location.province
|
||||
locationInfo.cityName = location.city
|
||||
locationInfo.cityCode = location.cityCode
|
||||
locationInfo.areaName = location.district
|
||||
locationInfo.areaCode = location.adCode
|
||||
locationInfo.street = location.street
|
||||
locationInfo.direction = location.bearing
|
||||
listener?.let {
|
||||
it.onChanged(locationInfo)
|
||||
}
|
||||
speed = location.speed
|
||||
speedListener?.let {
|
||||
it.onSpeedGet(location.speed)
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "定位失败 -> location is null")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun checkInit(): Boolean {
|
||||
return if (!init) {
|
||||
initLocation()
|
||||
init
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun getLocationInfo(): LocationInfo {
|
||||
return if (null != locationInfo) {
|
||||
locationInfo
|
||||
} else {
|
||||
if (null == locationClient) {
|
||||
locationClient = AMapLocationClient(mContext)
|
||||
this.locationClient = locationClient
|
||||
}
|
||||
var location = locationClient!!.lastKnownLocation
|
||||
location.toLocInfo(location)
|
||||
}
|
||||
}
|
||||
|
||||
//如果获取到的location address为空可以通过高德逆地理编码获得
|
||||
fun geoCodeLocation(
|
||||
latlngPoint: LatLonPoint,
|
||||
locGeoCode: (((locInfo: LocationInfo) -> Unit)),
|
||||
onError: ((msg: String) -> Unit)
|
||||
) {
|
||||
var geocoderSearch = GeocodeSearch(AbsMogoApplication.getApp().applicationContext)
|
||||
var regeocodeQuery = RegeocodeQuery(latlngPoint, 200f, GeocodeSearch.AMAP)
|
||||
geocoderSearch.getFromLocationAsyn(regeocodeQuery)
|
||||
geocoderSearch.setOnGeocodeSearchListener(object : GeocodeSearch.OnGeocodeSearchListener {
|
||||
override fun onRegeocodeSearched(p0: RegeocodeResult?, p1: Int) {
|
||||
if (p1 == 1000) {
|
||||
var regeocodeAddress = p0?.regeocodeAddress
|
||||
regeocodeAddress?.let {
|
||||
var locInfo = regeocodeAddress.toLocInfo(regeocodeAddress, latlngPoint)
|
||||
locGeoCode.invoke(locInfo)
|
||||
}
|
||||
} else {
|
||||
onError.invoke("geoCode -> $p1")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGeocodeSearched(p0: GeocodeResult?, p1: Int) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getSpeed():Float{
|
||||
return speed
|
||||
}
|
||||
|
||||
fun setonSpeedlistenner(speedListener: SpeedListener) {
|
||||
this.speedListener = speedListener
|
||||
}
|
||||
|
||||
interface SpeedListener {
|
||||
fun onSpeedGet(speed: Float)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.network.Utils
|
||||
import com.zhidao.roadcondition.model.InformationBody
|
||||
import com.zhidao.roadcondition.model.LocationInfo
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_IMG
|
||||
import com.zhidao.roadcondition.model.proxy.INFO_TYPE_VIDEO
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyType
|
||||
import com.zhidao.roadcondition.util.StrategyPreferenceUtil.Companion.getStrategyValidity
|
||||
|
||||
var array: Array<LocationInfo> = arrayOf(
|
||||
LocationInfo(116.40320588562773, 39.96661385462713, "测试数据1", 123123213),
|
||||
LocationInfo(116.41309250805662, 39.970285228355976, "测试数据2", 123123213),
|
||||
LocationInfo(116.40749205563353, 39.97317943101997, "测试数据3", 12321321321),
|
||||
LocationInfo(116.39925230953978, 39.97314654304226, "测试数据4", 123123123),
|
||||
LocationInfo(116.439366, 39.868472, "测试数据5", 123123123),
|
||||
LocationInfo(116.288164, 39.910547, "测试数据6", 123123123),
|
||||
LocationInfo(116.330132, 39.989311, "测试数据7", 123123123)
|
||||
)
|
||||
|
||||
fun getInformationBody(
|
||||
types: Int,
|
||||
urls: Map<String, String>,
|
||||
locationInfo: LocationInfo,
|
||||
isCustom: Boolean,
|
||||
trafficInfoType:String = "",
|
||||
isShare:Boolean,
|
||||
poiType: String,
|
||||
mainInfoId: Long
|
||||
): InformationBody {
|
||||
var jsonArray = JsonArray()
|
||||
var type: Int
|
||||
type = if (types == INFO_TYPE_VIDEO) {
|
||||
var videoObject = JsonObject()
|
||||
videoObject.addProperty("thumbnail", urls["thumb"])
|
||||
videoObject.addProperty("url", urls["video"])
|
||||
jsonArray.add(videoObject)
|
||||
INFO_TYPE_VIDEO
|
||||
} else {
|
||||
var urlObject = JsonObject()
|
||||
urlObject.addProperty("url", urls["pic"])
|
||||
jsonArray.add(urlObject)
|
||||
INFO_TYPE_IMG
|
||||
}
|
||||
var infoType = if (isCustom) 1 else 0
|
||||
return InformationBody(
|
||||
jsonArray.toString(),
|
||||
locationInfo.address,
|
||||
locationInfo.areaCode,
|
||||
locationInfo.areaName,
|
||||
locationInfo.cityCode,
|
||||
locationInfo.cityName,
|
||||
System.currentTimeMillis(),
|
||||
locationInfo.latitude,
|
||||
locationInfo.longitude,
|
||||
locationInfo.provinceName,
|
||||
Utils.getSn(),
|
||||
locationInfo.street,
|
||||
type,
|
||||
0,
|
||||
infoType,
|
||||
getStrategyValidity(AbsMogoApplication.getApp().applicationContext, convertUploadTypeOfSP(type), getStrategyType(convertUploadTypeOfSP(type))),
|
||||
trafficInfoType,
|
||||
isShare,
|
||||
locationInfo.direction,
|
||||
poiType,
|
||||
mainInfoId
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertUploadTypeOfSP(type: Int): String {
|
||||
return when (type) {
|
||||
INFO_TYPE_IMG -> "pic"
|
||||
INFO_TYPE_VIDEO -> "video"
|
||||
else -> "pic"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.zhidao.roadcondition.aspect.DebugLog
|
||||
|
||||
const val FILE_NAME = "settings_data"
|
||||
const val FILE_NAME_NAVI = "settings_navi_data"
|
||||
const val FILE_NAME_ACTIVE = "settings_active_data"
|
||||
|
||||
const val NAVI_INFO = "NAVI_INFO" //沿途导航数据存储
|
||||
const val NAVI_INFO_STATUS = "NAVI_INFO_STATUS" //沿途导航路线是否存在
|
||||
|
||||
const val PARAM_AUTHORIZATION = "PARAM_AUTHORIZATION"
|
||||
const val PARAM_PROMOTION_CONTENT = "PARAM_PROMOTION_CONTENT"
|
||||
const val PARAM_ACTIVE_WEB_URL = "PARAM_ACTIVE_WEB_URL"
|
||||
const val PARAM_ACTIVE_IMG_URL = "PARAM_ACTIVE_IMG_URL"
|
||||
const val PARAM_ACTIVE_STATUS = "PARAM_ACTIVE_STATUS"
|
||||
|
||||
|
||||
const val LAST_ENTER_TIME = "LAST_ENTER_TIME"
|
||||
const val PIC_NUMBER = "PIC_NUMBER" //图片拍摄张数
|
||||
const val VIDEO_DURATION_DEFAULT = 15_000L //视频拍摄时长
|
||||
const val PIC_NUMBER_DEFAULT = 1L //图片拍摄张数
|
||||
|
||||
const val TIME_QUANTUM = "time_quantum" //时间段
|
||||
const val COUNT_DOWN_TIME = "count_down" //倒计时
|
||||
const val VOICE_TEXT = "voice_text" //语音播报内容
|
||||
const val IS_SAVE_SPLASH = "is_save_splash" //是否保存了
|
||||
|
||||
//播放开始时间
|
||||
const val PLAYER_START_TIME = "first_time"
|
||||
|
||||
|
||||
fun clearActiveInfo(context: Context = AbsMogoApplication.getApp().applicationContext) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_ACTIVE, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
clear()
|
||||
val clearActiveInfo = commit()
|
||||
Log.d(FILE_NAME_NAVI, "clearActiveInfo = $clearActiveInfo")
|
||||
}
|
||||
}
|
||||
|
||||
fun setActiveWebUrl(content: String, context: Context = AbsMogoApplication.getApp().applicationContext) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_ACTIVE, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putString(PARAM_ACTIVE_WEB_URL, content)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun setActiveStatus(status: Int, context: Context = AbsMogoApplication.getApp().applicationContext) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_ACTIVE, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(PARAM_ACTIVE_STATUS, status)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getActiveStatus(context: Context): Int {
|
||||
return context.getSharedPreferences(FILE_NAME_ACTIVE, Context.MODE_PRIVATE)
|
||||
.getInt(PARAM_ACTIVE_STATUS, 0)
|
||||
}
|
||||
|
||||
fun setPromotionContent(content: String, context: Context = AbsMogoApplication.getApp().applicationContext) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putString(PARAM_PROMOTION_CONTENT, content)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun isAuthorization(context: Context): Boolean {
|
||||
return context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getBoolean(PARAM_AUTHORIZATION, false)
|
||||
}
|
||||
|
||||
@DebugLog
|
||||
fun setAuthorization(context: Context, authorization: Boolean) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putBoolean(PARAM_AUTHORIZATION, authorization)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@DebugLog
|
||||
fun setNaviInfo(context: Context, naviInfo: String) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_NAVI, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
val naviInfoSave = putString(NAVI_INFO, naviInfo)
|
||||
.commit()
|
||||
Log.d(FILE_NAME_NAVI, "naviInfoSave = $naviInfoSave")
|
||||
}
|
||||
}
|
||||
|
||||
@DebugLog
|
||||
fun setNaviInfoStatus(context: Context, naviInfoStatus: Boolean) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_NAVI, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
val naviInfoSaveStatus = putBoolean(NAVI_INFO_STATUS, naviInfoStatus)
|
||||
.commit()
|
||||
Log.d(FILE_NAME_NAVI, "naviInfoSaveStatus = $naviInfoSaveStatus")
|
||||
}
|
||||
}
|
||||
|
||||
fun clearAllNaviInfo(context: Context) {
|
||||
var sharedPreferences = context.getSharedPreferences(FILE_NAME_NAVI, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
clear()
|
||||
val naviInfoAllClear = commit()
|
||||
Log.d(FILE_NAME_NAVI, "naviInfoAllClear = $naviInfoAllClear")
|
||||
}
|
||||
}
|
||||
|
||||
fun putLong(key: String, value: Long) {
|
||||
var sharedPreferences =
|
||||
AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putLong(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun getLong(key: String, defaultValue: Long): Long {
|
||||
return AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getLong(key, defaultValue)
|
||||
}
|
||||
|
||||
|
||||
fun putInt(key: String, value: Int) {
|
||||
var sharedPreferences =
|
||||
AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getInt(key: String, defaultValue: Int): Int {
|
||||
return AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getInt(key, defaultValue)
|
||||
}
|
||||
|
||||
fun putCommonString(key: String, value: String) {
|
||||
var sharedPreferences =
|
||||
AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putString(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
//fun getCommonString(key: String?, defaultValue: String?): String {
|
||||
// return AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
// .getString(key, defaultValue)
|
||||
//}
|
||||
//
|
||||
//fun putCommonBoolean(key: String, value: Boolean) {
|
||||
// var sharedPreferences =
|
||||
// AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
// sharedPreferences.edit {
|
||||
// putBoolean(key, value).apply()
|
||||
// }
|
||||
//}
|
||||
|
||||
fun getCommonBoolean(key: String, defaultValue: Boolean): Boolean {
|
||||
return AbsMogoApplication.getApp().applicationContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getBoolean(key, defaultValue)
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
|
||||
const val STRATEGY_FILE_NAME = "strategy_data"
|
||||
|
||||
const val STRATEGY_TYPE_COPY = "strategy_data_copy"
|
||||
|
||||
/**
|
||||
* 策略SP存储模式:STRATEGY_TYPE + 策略类型 + 情报类型 + 对应项
|
||||
*/
|
||||
const val STRATEGY_TYPE = "STRATEGY_"
|
||||
|
||||
const val FREQUENCY = "FREQUENCY"
|
||||
const val DEFAULT_FREQUENCY_PIC = 2 //默认上报类型:周期性上报
|
||||
const val DEFAULT_FREQUENCY_VIDEO = 1 //默认上报类型:单次上报
|
||||
|
||||
const val INTERVAL = "INTERVAL"
|
||||
const val DEFAULT_INTERVAL_PIC = 600_000L //默认图片定时任务默认间隔
|
||||
const val DEFAULT_INTERVAL_VIDEO = 900_000L //默认视频定时任务默认间隔
|
||||
|
||||
const val VALIDITY = "VALIDITY"
|
||||
const val DEFAULT_VALIDITY = 4 * 60 //默认情报有效期:4小时
|
||||
|
||||
const val MAX_SPEED = "MAX_SPEED"
|
||||
const val MIN_SPEED = "MIN_SPEED"
|
||||
const val DEFAULT_MAX_SPEED = -1
|
||||
const val DEFAULT_MIN_SPEED = -1
|
||||
|
||||
|
||||
class StrategyPreferenceUtil {
|
||||
companion object {
|
||||
//保存策略类型,在AccOff的时候清除数据,更新时需要在没有情报上传时操作
|
||||
fun setStrategyType(context: Context, strategyType: Int, type: String) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_TYPE_COPY, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(STRATEGY_TYPE + type, strategyType).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyType(
|
||||
type: String,
|
||||
context: Context = AbsMogoApplication.getApp().applicationContext
|
||||
): Int {
|
||||
return context.getSharedPreferences(STRATEGY_TYPE_COPY, Context.MODE_PRIVATE)
|
||||
.getInt(STRATEGY_TYPE + type, 1)
|
||||
}
|
||||
|
||||
fun clearStrategyType(context: Context) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_TYPE_COPY, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
clear()
|
||||
val clearStrategyType = commit()
|
||||
Log.d(STRATEGY_TYPE_COPY, "clearStrategyType = $clearStrategyType")
|
||||
}
|
||||
}
|
||||
|
||||
fun setStrategyFrequency(
|
||||
context: Context,
|
||||
strategyType: Int,
|
||||
infoType: String,
|
||||
frequency: Int
|
||||
) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + FREQUENCY,
|
||||
frequency
|
||||
).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyFrequency(context: Context, infoType: String, strategyType: Int = 1): Int {
|
||||
return context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + FREQUENCY,
|
||||
convertFrequencyOfInfoType(infoType)
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertFrequencyOfInfoType(infoType: String): Int {
|
||||
return when (infoType) {
|
||||
"pic" -> DEFAULT_FREQUENCY_PIC
|
||||
"video" -> DEFAULT_FREQUENCY_VIDEO
|
||||
else -> DEFAULT_FREQUENCY_PIC
|
||||
}
|
||||
}
|
||||
|
||||
fun setStrategyInterval(
|
||||
context: Context,
|
||||
strategyType: Int,
|
||||
infoType: String,
|
||||
interval: Long
|
||||
) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putLong(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + INTERVAL,
|
||||
interval
|
||||
).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyInterval(context: Context, infoType: String, strategyType: Int = 1): Long {
|
||||
return context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getLong(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + INTERVAL,
|
||||
convertIntervalOfInfoType(infoType)
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertIntervalOfInfoType(infoType: String): Long {
|
||||
return when (infoType) {
|
||||
"pic" -> DEFAULT_INTERVAL_PIC
|
||||
"video" -> DEFAULT_INTERVAL_VIDEO
|
||||
else -> DEFAULT_INTERVAL_PIC
|
||||
}
|
||||
}
|
||||
|
||||
fun setStrategyValidity(
|
||||
context: Context,
|
||||
strategyType: Int,
|
||||
infoType: String,
|
||||
validity: Int
|
||||
) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + VALIDITY,
|
||||
validity
|
||||
).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyValidity(context: Context, infoType: String, strategyType: Int = 1): Int {
|
||||
return context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + VALIDITY,
|
||||
DEFAULT_VALIDITY
|
||||
)
|
||||
}
|
||||
|
||||
fun setStrategyMaxSpeed(
|
||||
context: Context,
|
||||
strategyType: Int,
|
||||
infoType: String,
|
||||
maxSpeed: Int
|
||||
) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + MAX_SPEED,
|
||||
maxSpeed
|
||||
).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyMaxSpeed(context: Context, infoType: String, strategyType: Int = 1): Int {
|
||||
return context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + MAX_SPEED,
|
||||
DEFAULT_MAX_SPEED
|
||||
)
|
||||
}
|
||||
|
||||
fun setStrategyMinSpeed(
|
||||
context: Context,
|
||||
strategyType: Int,
|
||||
infoType: String,
|
||||
minSpeed: Int
|
||||
) {
|
||||
var sharedPreferences =
|
||||
context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
sharedPreferences.edit {
|
||||
putInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + MIN_SPEED,
|
||||
minSpeed
|
||||
).commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun getStrategyMinSpeed(context: Context, infoType: String, strategyType: Int = 1): Int {
|
||||
return context.getSharedPreferences(STRATEGY_FILE_NAME, Context.MODE_PRIVATE)
|
||||
.getInt(
|
||||
STRATEGY_TYPE + strategyType + "_" + infoType + MIN_SPEED,
|
||||
DEFAULT_MIN_SPEED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.text.format.DateFormat
|
||||
|
||||
const val format = "yy/MM/dd kk:mm:ss"
|
||||
|
||||
fun formatDate(time: Long): String {
|
||||
return DateFormat.format(format, time).toString()
|
||||
}
|
||||
|
||||
fun convertVar(param: Any?): Any? {
|
||||
return if (param is String) {
|
||||
"\"$param\""
|
||||
} else {
|
||||
param
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
fun isReiceverRegist(context: Context, intentAction: String): Boolean {
|
||||
val intent = Intent()
|
||||
intent.action = intentAction
|
||||
val pm = context.packageManager
|
||||
val resolveInfos = pm.queryBroadcastReceivers(intent, 0)
|
||||
return resolveInfos != null && resolveInfos.isNotEmpty()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zhidao.roadcondition.util
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
@PublishedApi
|
||||
internal var ThreadPool =
|
||||
newFixedThreadPoolContext(Runtime.getRuntime().availableProcessors() * 2, "ThreadPool")
|
||||
|
||||
|
||||
/**
|
||||
* 在主线程中顺序执行,协程函数,一般用于最外层
|
||||
* 该函数会阻塞代码继续执行
|
||||
*/
|
||||
inline fun taskBlockOnMainThread(delayTime: Long = 0, noinline job: suspend () -> Unit) = runBlocking {
|
||||
delay(delayTime)
|
||||
job()
|
||||
}
|
||||
|
||||
/**
|
||||
* 并发执行,常用于最外层
|
||||
* 特点带返回值
|
||||
*/
|
||||
inline fun <T> taskAsync(delayTime: Long = 0, noinline job: suspend () -> T) = GlobalScope.async(ThreadPool) {
|
||||
delay(delayTime)
|
||||
job()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user