diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86/libserial_port.so b/app/src/main/jniLibs/x86/libserial_port.so deleted file mode 100755 index 47e985a..0000000 --- a/app/src/main/jniLibs/x86/libserial_port.so +++ /dev/null Binary files differ diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86/libserial_port.so b/app/src/main/jniLibs/x86/libserial_port.so deleted file mode 100755 index 47e985a..0000000 --- a/app/src/main/jniLibs/x86/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86_64/libserial_port.so b/app/src/main/jniLibs/x86_64/libserial_port.so deleted file mode 100755 index 558eb36..0000000 --- a/app/src/main/jniLibs/x86_64/libserial_port.so +++ /dev/null Binary files differ diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86/libserial_port.so b/app/src/main/jniLibs/x86/libserial_port.so deleted file mode 100755 index 47e985a..0000000 --- a/app/src/main/jniLibs/x86/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86_64/libserial_port.so b/app/src/main/jniLibs/x86_64/libserial_port.so deleted file mode 100755 index 558eb36..0000000 --- a/app/src/main/jniLibs/x86_64/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml index 228c2c4..b0b948c 100644 --- a/app/src/main/res/layout/activity_big_image.xml +++ b/app/src/main/res/layout/activity_big_image.xml @@ -26,7 +26,7 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="@dimen/lib_dp_10" - android:src="@drawable/ic_left_white" /> + android:src="@drawable/ic_title_left" /> + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86/libserial_port.so b/app/src/main/jniLibs/x86/libserial_port.so deleted file mode 100755 index 47e985a..0000000 --- a/app/src/main/jniLibs/x86/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86_64/libserial_port.so b/app/src/main/jniLibs/x86_64/libserial_port.so deleted file mode 100755 index 558eb36..0000000 --- a/app/src/main/jniLibs/x86_64/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml index 228c2c4..b0b948c 100644 --- a/app/src/main/res/layout/activity_big_image.xml +++ b/app/src/main/res/layout/activity_big_image.xml @@ -26,7 +26,7 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="@dimen/lib_dp_10" - android:src="@drawable/ic_left_white" /> + android:src="@drawable/ic_title_left" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10a1363..18c6ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ *.iml .gradle /local.properties -/.idea +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild .cxx -local.properties /app/build /app/src/androidTest /app/src/test \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..f766fc3 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..167cf0c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b007d28 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..4515aa3 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 623fc18..59fdbea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,15 @@ apply plugin: 'org.greenrobot.greendao' android { +// signingConfigs { +// release { +// storeFile file('ElectricDetector.jks') +// storePassword '123456789' +// keyAlias 'key0' +// keyPassword '123456789' +// } +// } + compileSdkVersion 33 defaultConfig { @@ -13,12 +22,6 @@ targetSdkVersion 33 versionCode 5020 versionName "5.0.2" - - ndk { - moduleName "serial_port" - //"log"表示加入Android Logcat日志,需要导入 #include "android/log.h" - ldLibs "log" - } } buildTypes { @@ -28,6 +31,13 @@ } } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -43,8 +53,8 @@ } } - viewBinding { - enabled true + buildFeatures { + viewBinding true } applicationVariants.every { variant -> @@ -66,10 +76,10 @@ } dependencies { + //基础依赖库 + implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.8' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' - //基础依赖库 - implementation 'com.github.AndroidCoderPeng:Kotlin-lite-lib:1.0.5.3' //Google官方授权框架 implementation 'pub.devrel:easypermissions:3.0.0' //腾讯Android UI框架 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92d80c5..ba718ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,15 +63,17 @@ + + - - - + +#include +#include +#include +#include +#include +#include + +#include "android/log.h" + +#define LOG_TAG "SerialPortJNI" + +#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) +#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) + +static speed_t get_baud_rate(jint baud_rate) { + switch (baud_rate) { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, + jint baud_rate, jint flags) { + int fd; + speed_t speed; + jobject file_descriptor; + + speed = get_baud_rate(baud_rate); + if (speed == -1) { + LOG_E("invalid baud_rate"); + return nullptr; + } + + jboolean is_copy; + const char *path_utf = env->GetStringUTFChars(path, &is_copy); + fd = open(path_utf, O_RDWR | flags); + LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags); + env->ReleaseStringUTFChars(path, path_utf); + if (fd == -1) { + LOG_E("can not open Port"); + return nullptr; + } + + struct termios cfg{}; + LOG_D("configure serial port %d", fd); + if (tcgetattr(fd, &cfg)) { + LOG_E("tcgetattr() failed"); + close(fd); + return nullptr; + } + + cfmakeraw(&cfg); + cfsetispeed(&cfg, speed); + cfsetospeed(&cfg, speed); + + if (tcsetattr(fd, TCSANOW, &cfg)) { + LOG_E("tcsetattr() failed"); + close(fd); + return nullptr; + } + + //获取句柄 + jclass fd_class = env->FindClass("java/io/FileDescriptor"); + jmethodID fd_method_id = env->GetMethodID(fd_class, "", "()V"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I"); + + file_descriptor = env->NewObject(fd_class, fd_method_id); + env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd); + + return file_descriptor; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { + jclass serial_port_class = env->GetObjectClass(thiz); + jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor"); + + // fd 对应SerialPortKit里面的 fd + char fd_buffer[4] = {0}; + strcat(fd_buffer, "fd"); + jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer, + "Ljava/io/FileDescriptor;"); + + char descriptor_buffer[16] = {0}; + strcat(descriptor_buffer, "descriptor"); + jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I"); + + jobject fd_obj = env->GetObjectField(thiz, fd_field_id); + jint descriptor = env->GetIntField(fd_obj, descriptor_field_id); + + LOG_D("close(fd = %d)", descriptor); + close(descriptor); +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt index 0dbff79..1010ab7 100644 --- a/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/electric/detector/base/BaseApplication.kt @@ -48,10 +48,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts?.forEach { - it.close() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt index f6e6574..69a3ddd 100644 --- a/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/base/SerialPortActivity.kt @@ -17,8 +17,8 @@ abstract class SerialPortActivity : AppCompatActivity() { protected lateinit var binding: VB - - lateinit var out: OutputStream + private val serialPorts by lazy { BaseApplication.get().getSerialPorts() } + var out: OutputStream? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,18 +30,19 @@ initEvent() try { - val serialPorts = BaseApplication.get().getSerialPorts() //读 lifecycleScope.launch(Dispatchers.IO) { serialPorts?.apply { - val stream = this[0].inputStream + val stream = first().inputStream while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -57,10 +58,12 @@ while (isActive) { try { val buffer = ByteArray(64) - val size = stream.read(buffer) - if (size > 0) { - withContext(Dispatchers.Main) { - onDataReceived(buffer) + stream?.apply { + val size = read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + onDataReceived(buffer) + } } } } catch (e: IOException) { @@ -72,8 +75,10 @@ //写 serialPorts?.apply { - out = this[0].outputStream + out = first().outputStream } + + "串口已打开!".show(this) } catch (e: SecurityException) { "您没有串口的读写权限!".show(this) } catch (e: IOException) { @@ -114,7 +119,9 @@ abstract fun onDataReceived(buffer: ByteArray) override fun onDestroy() { - BaseApplication.get().closeSerialPort() + serialPorts?.forEach { + it.closeSerialPort() + } super.onDestroy() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java deleted file mode 100644 index 64e7181..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/IAddressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.electric.detector.callback; - -public interface IAddressListener { - void onGetAddress(String address); -} diff --git a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt deleted file mode 100644 index 6f1bd03..0000000 --- a/app/src/main/java/com/casic/electric/detector/callback/ILocationListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.casic.electric.detector.callback - -import com.amap.api.location.AMapLocation - -interface ILocationListener { - fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java new file mode 100644 index 0000000..7a4e313 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetAddressListener.java @@ -0,0 +1,5 @@ +package com.casic.electric.detector.callback; + +public interface OnGetAddressListener { + void onGetAddress(String address); +} diff --git a/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt new file mode 100644 index 0000000..a8ec79e --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/callback/OnGetLocationListener.kt @@ -0,0 +1,7 @@ +package com.casic.electric.detector.callback + +import com.amap.api.location.AMapLocation + +interface OnGetLocationListener { + fun onAMapLocationGet(location: AMapLocation?) //高德定位数据 +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt index c96c6f5..fba0059 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/AMapLocation.kt @@ -3,24 +3,15 @@ import com.amap.api.location.AMapLocation import com.amap.api.maps.AMapUtils import com.amap.api.maps.model.LatLng -import com.casic.electric.detector.model.CalculateResult import kotlin.math.acos /** - * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 - * C B - * |-------/ - * | / - * | / - * | / - * | / - * | / - * | / - * |/ - * A + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是5米内),球面近似为平面 + * A(探测仪所在位置),B(最近的标识器位置),C(辅助点位置) + * 手机坐标轴Y轴反置,所以右下角才是第一象限 * */ -fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { - //构造直角辅助点 +fun AMapLocation.calculateAngle(target: LatLng): Int { + //构造直角辅助点C val auxiliaryPoint = LatLng(target.latitude, this.longitude) //AB线段长度 @@ -30,10 +21,10 @@ //AC线段长度 val auxiliaryDistance = AMapUtils.calculateLineDistance( - LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + auxiliaryPoint, target ) - //求余弦值 + //求∠A的余弦值 val cosine = auxiliaryDistance / distance //反余弦得弧度 @@ -43,17 +34,18 @@ val angle = (radian * 180) / Math.PI //判断方位 - val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + val direction = if (this.longitude < target.longitude && this.latitude < target.latitude) { //东北方 - "东偏北" - } else if (target.latitude < this.latitude && target.longitude < this.longitude) { - //西南方 - "西偏南" - } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + angle.toInt() + } else if (this.longitude > target.longitude && this.latitude < target.latitude) { //西北方 - "西偏北" + (angle + 90).toInt() + } else if (this.longitude > target.longitude && this.latitude > target.latitude) { + //西南方 + (angle + 180).toInt() } else { - "东偏南" + //东南方 + (angle + 270).toInt() } - return CalculateResult(angle.toInt(), direction, distance.toInt()) + return direction } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/extensions/String.kt b/app/src/main/java/com/casic/electric/detector/extensions/String.kt index 838d3ad..55136a6 100644 --- a/app/src/main/java/com/casic/electric/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/electric/detector/extensions/String.kt @@ -43,6 +43,7 @@ val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { FileType.APK -> "$httpConfig/ems/${this}" + FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" FileType.IMAGE -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt b/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt deleted file mode 100644 index 50682fd..0000000 --- a/app/src/main/java/com/casic/electric/detector/extensions/Throwable.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.casic.electric.detector.extensions - -import java.net.ConnectException - -fun Throwable.convertChinese(): String { - this.printStackTrace() - return when (this) { - is ConnectException -> "连接失败,请检查网络或者服务器" - else -> "服务器异常,请联系管理员" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt deleted file mode 100644 index 84c9cd9..0000000 --- a/app/src/main/java/com/casic/electric/detector/model/CalculateResult.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.casic.electric.detector.model - -data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/electric/detector/model/EventModel.java b/app/src/main/java/com/casic/electric/detector/model/EventModel.java new file mode 100644 index 0000000..27a53e4 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/EventModel.java @@ -0,0 +1,76 @@ +package com.casic.electric.detector.model; + +public class EventModel { + private Long id; + private Long taskId; + private String description; + private String createTime; + private String imageName; + private Double latitude; + private Double longitude; + private Integer status; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/app/src/main/java/com/casic/electric/detector/model/TaskModel.java b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java new file mode 100644 index 0000000..65f5ae7 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/model/TaskModel.java @@ -0,0 +1,265 @@ +package com.casic.electric.detector.model; + +import java.util.List; + +public class TaskModel { + + private String success; + private List message; + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public List getMessage() { + return message; + } + + public void setMessage(List message) { + this.message = message; + } + + public static class MessageModel { + private int id; + private String taskCode; + private String description; + private String deployDate; + private Object beginDate; + private Object endDate; + private String status; + private String creatorId; + private String creatorName; + private String patrolerId; + private String patrolerName; + private int isValid; + private List taskDetailInfos; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeployDate() { + return deployDate; + } + + public void setDeployDate(String deployDate) { + this.deployDate = deployDate; + } + + public Object getBeginDate() { + return beginDate; + } + + public void setBeginDate(Object beginDate) { + this.beginDate = beginDate; + } + + public Object getEndDate() { + return endDate; + } + + public void setEndDate(Object endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatorId() { + return creatorId; + } + + public void setCreatorId(String creatorId) { + this.creatorId = creatorId; + } + + public String getCreatorName() { + return creatorName; + } + + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + public String getPatrolerId() { + return patrolerId; + } + + public void setPatrolerId(String patrolerId) { + this.patrolerId = patrolerId; + } + + public String getPatrolerName() { + return patrolerName; + } + + public void setPatrolerName(String patrolerName) { + this.patrolerName = patrolerName; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + public List getTaskDetailInfos() { + return taskDetailInfos; + } + + public void setTaskDetailInfos(List taskDetailInfos) { + this.taskDetailInfos = taskDetailInfos; + } + + public static class TaskDetailInfosModel { + private int id; + private String taskId; + private String taskCode; + private Object markerName; + private int markerId; + private String markerIdReal; + private double longitude; + private double latitude; + private int isChecked; + private int isNormal; + private Object imagePath; + private Object description; + private Object finishTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public Object getMarkerName() { + return markerName; + } + + public void setMarkerName(Object markerName) { + this.markerName = markerName; + } + + public int getMarkerId() { + return markerId; + } + + public void setMarkerId(int markerId) { + this.markerId = markerId; + } + + public String getMarkerIdReal() { + return markerIdReal; + } + + public void setMarkerIdReal(String markerIdReal) { + this.markerIdReal = markerIdReal; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public int getIsChecked() { + return isChecked; + } + + public void setIsChecked(int isChecked) { + this.isChecked = isChecked; + } + + public int getIsNormal() { + return isNormal; + } + + public void setIsNormal(int isNormal) { + this.isNormal = isNormal; + } + + public Object getImagePath() { + return imagePath; + } + + public void setImagePath(Object imagePath) { + this.imagePath = imagePath; + } + + public Object getDescription() { + return description; + } + + public void setDescription(Object description) { + this.description = description; + } + + public Object getFinishTime() { + return finishTime; + } + + public void setFinishTime(Object finishTime) { + this.finishTime = finishTime; + } + } + } +} diff --git a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt index 7836b28..26a2bdd 100644 --- a/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/electric/detector/retrofit/RetrofitServiceManager.kt @@ -1,7 +1,6 @@ package com.casic.electric.detector.retrofit import com.casic.electric.detector.extensions.reformat -import com.casic.electric.detector.utils.LabelDataClass import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.JsonObject @@ -75,52 +74,62 @@ * 安装新标识器 * Multipart上传图片,文件,带多参数上传 */ - suspend fun installLabel(labelData: LabelDataClass): String { + suspend fun installLabel( + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ): String { val param = JsonObject() - param.addProperty("companyId", labelData.companyId) - param.addProperty("recordType", labelData.recordType) - param.addProperty("markerObjectId", labelData.markerObjectId) - param.addProperty("objectName", labelData.objectName) - param.addProperty("pressLevel", labelData.pressLevel) - param.addProperty("markerObjectType", labelData.markerObjectType) - param.addProperty("inlineName", labelData.inlineName) - param.addProperty("wellMaterial", labelData.wellMaterial) - param.addProperty("capacity", labelData.capacity) - param.addProperty("transformerSpec", labelData.transformerSpec) - param.addProperty("size", labelData.size) - param.addProperty("inlineCount", labelData.inlineCount) - param.addProperty("outlineCount", labelData.outlineCount) - param.addProperty("cabinetType", labelData.cabinetType) - param.addProperty("bottomDepth", labelData.bottomDepth) - param.addProperty("holeCount", labelData.holeCount) - param.addProperty("coverDepth", labelData.coverDepth) - param.addProperty("crossPipe", labelData.crossPipe) - param.addProperty("leftHoleCount", labelData.leftHoleCount) - param.addProperty("tieCable1", labelData.tieCable1) - param.addProperty("tieCable2", labelData.tieCable2) - param.addProperty("jointCount", labelData.jointCount) - param.addProperty("bushingMaterial", labelData.bushingMaterial) - param.addProperty("bushingSpec", labelData.bushingSpec) - param.addProperty("height", labelData.height) - param.addProperty("lineNo", labelData.lineNo) - param.addProperty("constructTime", labelData.constructTime) - param.addProperty("operComp", labelData.operComp) - param.addProperty("area", labelData.area) - param.addProperty("road", labelData.road) - param.addProperty("memo1", labelData.memo1) - param.addProperty("memo2", labelData.memo2) - param.addProperty("memo3", labelData.memo3) - param.addProperty("markerId", labelData.markerId) - param.addProperty("markerType", labelData.markerType) - param.addProperty("owner", labelData.owner) - param.addProperty("markerDepth", labelData.markerDepth) - param.addProperty("createTime", labelData.createTime) - param.addProperty("longitude", labelData.longitude) - param.addProperty("latitude", labelData.latitude) - param.addProperty("eleTagCount", labelData.eleTagCount) - param.addProperty("markerMemo1", labelData.markerMemo1) - param.addProperty("markerMemo2", labelData.markerMemo2) - param.addProperty("markerMemo3", labelData.markerMemo3) + param.addProperty("companyId", companyId) + param.addProperty("recordType", recordType) + param.addProperty("markerObjectType", markerObjectType) + param.addProperty("pipeMaterial", pipeMaterial) + param.addProperty("pipeDiameter", pipeDiameter) + param.addProperty("depth", depth) + param.addProperty("belowType", belowType) + param.addProperty("belowMaterial", belowMaterial) + param.addProperty("belowDiameter", belowDiameter) + param.addProperty("belowDepth", belowDepth) + param.addProperty("layStyle", layStyle) + param.addProperty("area", area) + param.addProperty("line", line) + param.addProperty("road", road) + param.addProperty("constructTime", constructTime) + param.addProperty("ownerComp", ownerComp) + param.addProperty("markerObjectId", markerObjectId) + param.addProperty("markerId", markerId) + param.addProperty("markerType", markerType) + param.addProperty("markerDepth", markerDepth) + param.addProperty("creator", creator) + param.addProperty("createTime", createTime) + param.addProperty("longitude", longitude) + param.addProperty("latitude", latitude) + param.addProperty("colorType", colorType) + param.addProperty("memo", memo) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) @@ -128,7 +137,7 @@ res["jsonMarker"] = requestBody val multiParts = ArrayList() - labelData.realPaths.forEachIndexed { index, s -> + realPaths.forEachIndexed { index, s -> val file = File(s) val fileMultipart = MultipartBody.Part.createFormData( "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) diff --git a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java index 921448f..83cda4a 100644 --- a/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java +++ b/app/src/main/java/com/casic/electric/detector/uart/SerialPort.java @@ -13,31 +13,32 @@ public class SerialPort { private static final String TAG = "SerialPort"; - /** - * .so 库名字。需要去掉生成时自带的lib前缀 - * */ static { - System.loadLibrary("serial_port"); + System.loadLibrary("serialPort"); } /** - * JNI - *

- * 必须用 native 标识JNI方法 + * 打开串口 */ - private native static FileDescriptor open(String path, int baudRate, int flags); - - public native void close(); + private native FileDescriptor open(String path, int baudRate, int flags); /** - * Do not remove or rename the field mFd: it is used by native method close(); + * 关闭串口 */ - private FileDescriptor mFd; - private final FileInputStream mFileInputStream; - private final FileOutputStream mFileOutputStream; + private native void close(); - public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { + /** + * jfieldID fd_id = env->GetFieldID(serial_port_class, "fd", "Ljava/io/FileDescriptor;"); + *

+ * fd不能随意修改,要改就一起改 + *

+ * Do not remove or rename the field fd: it is used by native method close(); + */ + private final FileDescriptor fd; + private final FileInputStream inputStream; + private final FileOutputStream outputStream; + public SerialPort(File device, int baudRate, int flags) throws SecurityException, IOException { if (!device.canRead() || !device.canWrite()) { try { Process su; @@ -54,20 +55,24 @@ } } - mFd = open(device.getAbsolutePath(), baudrate, flags); - if (mFd == null) { + fd = open(device.getAbsolutePath(), baudRate, flags); + if (fd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } - mFileInputStream = new FileInputStream(mFd); - mFileOutputStream = new FileOutputStream(mFd); + inputStream = new FileInputStream(fd); + outputStream = new FileOutputStream(fd); } public InputStream getInputStream() { - return mFileInputStream; + return inputStream; } public OutputStream getOutputStream() { - return mFileOutputStream; + return outputStream; + } + + public void closeSerialPort() { + close(); } } diff --git a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt index 8f6caba..f9e5457 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/DataBaseManager.kt @@ -90,21 +90,27 @@ LocaleConstant.CONDITION_ARRAY[1] -> { return queryByProperty(LabelBeanDao.Properties.MarkerNumber, value) } + LocaleConstant.CONDITION_ARRAY[2] -> { return queryByProperty(LabelBeanDao.Properties.ObjectName, value) } + LocaleConstant.CONDITION_ARRAY[3] -> { return queryByProperty(LabelBeanDao.Properties.Area, value) } + LocaleConstant.CONDITION_ARRAY[4] -> { return queryByProperty(LabelBeanDao.Properties.Road, value) } + LocaleConstant.CONDITION_ARRAY[5] -> { return queryByProperty(LabelBeanDao.Properties.InspectionUnit, value) } + LocaleConstant.CONDITION_ARRAY[6] -> { return queryByProperty(LabelBeanDao.Properties.Owner, value) } + LocaleConstant.CONDITION_ARRAY[8] -> { return queryByProperty(LabelBeanDao.Properties.MarkerId, value) } @@ -132,6 +138,15 @@ .where(LabelBeanDao.Properties.MarkerId.eq(markerId)) .list() } + + fun deleteTaskById(taskId: String?) { + if (taskId.isNullOrBlank()) { + return + } +// queryTaskById(taskId).forEach { +// taskBeanDao.delete(it) +// } + } /******************************* Lable *** End **********************************************/ /******************************* Small Lable *** Start **************************************/ diff --git a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt index 362df50..67c666e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/FileType.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/FileType.kt @@ -3,5 +3,7 @@ sealed class FileType { object APK : FileType() + object EXCEL : FileType() + object IMAGE : FileType() } diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt index 9356f9a..566996e 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocaleConstant.kt @@ -14,6 +14,7 @@ const val PERMISSIONS_CODE = 999 const val RADIUS_SIZE = 100 //相距多少米才聚合,单位:米 + const val MAX_DISTANCE = 5.5f //表盘最大显示距离 const val AUTO_SAVE = "AUTO_SAVE" const val USER_ACCOUNT = "USER_ACCOUNT" diff --git a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt index 61e55f6..b726026 100644 --- a/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt +++ b/app/src/main/java/com/casic/electric/detector/utils/LocationHub.kt @@ -11,8 +11,8 @@ import com.amap.api.services.geocoder.GeocodeSearch import com.amap.api.services.geocoder.RegeocodeQuery import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.electric.detector.callback.IAddressListener -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetAddressListener +import com.casic.electric.detector.callback.OnGetLocationListener class LocationHub constructor(context: Context) { @@ -20,10 +20,11 @@ private val locationClient by lazy { AMapLocationClient(context) } private val codeSearch by lazy { GeocodeSearch(context) } - fun getCurrentLocation(isOnceLocation: Boolean, listener: ILocationListener) { + fun getCurrentLocation(isOnceLocation: Boolean, listener: OnGetLocationListener) { val locationOption = AMapLocationClientOption() locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy locationOption.isOnceLocation = isOnceLocation + locationOption.isNeedAddress = false locationClient.setLocationOption(locationOption) locationClient.setLocationListener { if (it.errorCode == 0) { @@ -38,7 +39,7 @@ locationClient.startLocation() } - fun antiCodingLocation(location: Location, listener: IAddressListener) { + fun antiCodingLocation(location: Location, listener: OnGetAddressListener) { try { // 第一个参数表示一个LatLonPoint,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系 val query = RegeocodeQuery( diff --git a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt index d72edc5..33bf42d 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ElectricMarkerDetailActivity.kt @@ -16,6 +16,7 @@ import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant +//TODO 改为Dialog class ElectricMarkerDetailActivity : KotlinBaseActivity() { private lateinit var smallLabel: SmallLabelBean diff --git a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt index 286bf4a..837ae86 100644 --- a/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/InstallSmallLabelActivity.kt @@ -1,6 +1,5 @@ package com.casic.electric.detector.view -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.media.AudioAttributes @@ -21,8 +20,16 @@ import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.databinding.ActivityInstallSmallLabelBinding -import com.casic.electric.detector.extensions.* -import com.casic.electric.detector.utils.* +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.extensions.getDefaultValue +import com.casic.electric.detector.extensions.hexToString +import com.casic.electric.detector.extensions.setDefaultValue +import com.casic.electric.detector.extensions.show +import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.utils.DataBaseManager +import com.casic.electric.detector.utils.GpioManager +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.SmallLabelDataClass import com.casic.electric.detector.vm.TaskViewModel import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType @@ -44,7 +51,7 @@ import java.io.FileWriter import java.io.IOException -@SuppressLint("SetTextI18n") +//TODO 改为Dialog class InstallSmallLabelActivity : SerialPortActivity(), Handler.Callback { @@ -302,8 +309,8 @@ weakReferenceHandler.postDelayed({ try { // 发送读标识器或搜索信号 - out.write("2".toByteArray()) - out.flush() + out?.write("2".toByteArray()) + out?.flush() } catch (e: IOException) { e.printStackTrace() } @@ -312,12 +319,10 @@ } override fun onDataReceived(buffer: ByteArray) { - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023081702 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } + val message = weakReferenceHandler.obtainMessage() + message.what = 2023081702 + message.obj = buffer + weakReferenceHandler.sendMessage(message) } override fun handleMessage(msg: Message): Boolean { diff --git a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt index 9c98b5f..6cbfd3f 100644 --- a/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/LoginActivity.kt @@ -68,7 +68,7 @@ SaveKeyValues.putValue(LocaleConstant.SERVER_PORT, serversPort) //登陆 - userViewModel.login(account, password) + userViewModel.login(this, account, password) } } diff --git a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt index 40a5f3d..d3ffdd3 100644 --- a/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/MainActivity.kt @@ -9,11 +9,16 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle import android.os.CountDownTimer -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.KeyEvent import android.view.View import android.view.animation.Animation @@ -26,16 +31,17 @@ import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.BitmapDescriptorFactory import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MyLocationStyle import com.casic.electric.detector.R import com.casic.electric.detector.adapter.EditableImageAdapter import com.casic.electric.detector.base.SerialPortActivity import com.casic.electric.detector.bean.LabelBean -import com.casic.electric.detector.bean.SmallLabelBean import com.casic.electric.detector.bean.TaskBean -import com.casic.electric.detector.callback.ILocationListener +import com.casic.electric.detector.callback.OnGetLocationListener import com.casic.electric.detector.callback.OnImageCompressListener import com.casic.electric.detector.cluster.ClusterItem import com.casic.electric.detector.cluster.ClusterOverlay @@ -55,6 +61,7 @@ import com.casic.electric.detector.extensions.setDefaultValue import com.casic.electric.detector.extensions.show import com.casic.electric.detector.extensions.toHex +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.ExcelHub import com.casic.electric.detector.utils.GpioManager @@ -87,6 +94,7 @@ import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog @@ -102,34 +110,40 @@ import java.util.TimerTask @SuppressLint("all") -class MainActivity : SerialPortActivity() { +class MainActivity : SerialPortActivity(), SensorEventListener, + Handler.Callback { private val kTag = "MainActivity" private val context = this@MainActivity - private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub(this) } private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private val backDrawables by lazy { HashMap() } - private val installMarkerDialog by lazy { InstallMarkerDialog(this) } - private val installSmallMarkerDialog by lazy { InstallSmallMarkerDialog(this) } + private val installDialog by lazy { InstallMarkerDialog(this) } private val searchDialog by lazy { SearchMarkerDialog(this) } + private val sensorMessageCode = 2024022301 + private val rotationMatrix = FloatArray(9)//旋转矩阵缓存 + private val valueArray = FloatArray(3)//方位角数值 private var clickTime: Long = 0 - private var labels = ArrayList() - private var smallLabels = ArrayList() + private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null private var latitude: Double = 0.0 private var longitude: Double = 0.0 private var isFreeTask = false - private var ids = ArrayList() + private var ids = HashSet() private var signalTask: TimerTask? = null private var searchMarkerTimer: Timer? = null + private var taskId: String? = null + private var gravity: FloatArray? = null + private var geomagnetic: FloatArray? = null private lateinit var aMap: AMap - private lateinit var taskBean: TaskBean - private lateinit var taskId: String + private lateinit var task: TaskBean + private lateinit var sensorManager: SensorManager + private lateinit var weakReferenceHandler: WeakReferenceHandler /***inner class 需要用到*****start*/ + private val gpioManager by lazy { GpioManager() } + private val locationHub by lazy { LocationHub(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() @@ -137,6 +151,7 @@ private var soundResourceId = 0 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 + private var isExecuteTask = false /***inner class 需要用到*****end*/ @@ -153,9 +168,12 @@ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1) fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1) + "登录成功".show(this) + //地图初始化 initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -182,9 +200,9 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - labels = ExcelHub.readLabel(file.absolutePath) + labelBeans = ExcelHub.readLabel(file.absolutePath) withContext(Dispatchers.IO) { - labels.forEach { label -> + labelBeans.forEach { label -> DataBaseManager.get.insertLabel(label) } } @@ -209,12 +227,12 @@ FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { lifecycleScope.launch { - smallLabels = ExcelHub.readSmallLabel(file.absolutePath) - withContext(Dispatchers.IO) { - smallLabels.forEach { label -> - DataBaseManager.get.insertSmallLabel(label) - } - } +// smallLabels = ExcelHub.readSmallLabel(file.absolutePath) +// withContext(Dispatchers.IO) { +// smallLabels.forEach { label -> +// DataBaseManager.get.insertSmallLabel(label) +// } +// } } } @@ -229,38 +247,59 @@ } } } -// taskViewModel.taskResult.observe(this) { -// if (it.success == "true") { -// //清空之前的数据 + taskViewModel.taskResult.observe(this) { + if (it.success == "true") { + //清空之前的数据 // DataBaseManager.get.clearTasks() -// AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") -// .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") -// .setOnDialogButtonClickListener(object : -// AlertMessageDialog.OnDialogButtonClickListener { -// override fun onConfirmClick() { -// saveTaskInformation(it) -// } -// }).build().show() -// } -// } + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("您有${it.message.size}个新任务!").setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + saveTaskInformation(it) + } + }).build().show() + } + } taskViewModel.freeTaskResult.observe(this) { taskId = it } taskViewModel.uploadTaskMarkerResult.observe(this) { "自由巡检任务已完成".show(this) ids.clear() + //清空自由巡检添加的Marker + aMap.clear() + showLabelsOnMap() + } + + taskViewModel.executeTaskResult.observe(this) { + "工单任务已完成".show(this) + aMap.clear() + showLabelsOnMap() } } override fun initEvent() { binding.rightImageView.setOnClickListener { - lifecycleScope.launch(Dispatchers.Main) { - val labels = withContext(Dispatchers.IO) { - DataBaseManager.get.queryLabelById("0") + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + lifecycleScope.launch(Dispatchers.Main) { + val labels = withContext(Dispatchers.IO) { + DataBaseManager.get.queryLabelById("0") + } + if (labels.isNotEmpty()) { + samplePopupWindow.setShowPosition(4) + } + val x = + binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } - if (labels.isNotEmpty()) { - samplePopupWindow.setShowPosition(4) - } - val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -269,9 +308,9 @@ override fun onPopupItemClicked(position: Int) { when (position) { 0 -> updateLabels() -// 1 -> downloadTask() + 1 -> downloadTask() 2 -> navigatePageTo() -// 3 -> uploadEvent() + 3 -> uploadEvent() // 4 -> uploadLabel() } } @@ -288,7 +327,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installMarkerDialog.show() +// installMarkerDialog.show() } override fun onCancelClick() { @@ -296,7 +335,7 @@ /** * 改为Dialog方式,避免频繁打开/关闭串口 * */ - installSmallMarkerDialog.show() +// installSmallMarkerDialog.show() } }).build().show() } @@ -312,7 +351,7 @@ ) { //查询数据库 lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { if (contentValue.size == 1) { DataBaseManager.get.loadLabelByCondition( selectedCondition, contentValue[0] @@ -327,7 +366,7 @@ val latitudeList = ArrayList() val longitudeList = ArrayList() - labels.forEach { + labelBeans.forEach { val latitude = it.latitude val longitude = it.longitude if (latitude.isNotBlank() && longitude.isNotBlank()) { @@ -413,13 +452,26 @@ binding.detectionButton.setOnClickListener { /** * 改为Dialog方式,避免频繁打开/关闭串口 + * + * 如果开启自由巡检就不让探测 * */ - searchDialog.show() + if (isFreeTask) { + AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + + } + }).build().show() + } else { + searchDialog.show() + } } //自由巡检 binding.stopFreeTaskButton.setOnLongClickListener { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") + AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示") .setMessage("是否确定结束此次自由巡检任务?").setPositiveButton("是") .setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { @@ -430,8 +482,15 @@ //降低串口电位 gpioManager.setGpioLow("18") - taskViewModel.uploadTaskMarker(taskId, ids) binding.stopFreeTaskButton.visibility = View.GONE + if (taskId.isNullOrBlank()) { + "任务ID异常,无法提交任务,请联系服务器管理员".show(context) + return + } + + taskId?.apply { + taskViewModel.uploadTaskMarker(context, this, ArrayList(ids)) + } } }).build().show() true @@ -445,18 +504,17 @@ .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { override fun onConfirmClick(value: String) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String - taskViewModel.createFreeTask(userId, value) + taskViewModel.createFreeTask(context, userId, value) //调高串口电位 gpioManager.setGpioHigh("18") - soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) isFreeTask = true //自由巡检 signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } searchMarkerTimer = Timer() @@ -473,23 +531,34 @@ override fun onDataReceived(buffer: ByteArray) { val hex = buffer.toHex() - Log.d(kTag, "$kTag => $hex") if (searchDialog.isDetectMarker) { searchDialog.bindingValue(hex) - } else if (installMarkerDialog.isReadMarker) { + } else if (installDialog.isReadMarker) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { - installMarkerDialog.bindingValue(markerId) - } - } else if (installSmallMarkerDialog.isReadMarker) { - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - installSmallMarkerDialog.bindingValue(markerId) + installDialog.bindingValue(markerId) } } else if (isFreeTask) { val markerId = hex.take(20).hexToString() if (markerId.isNumber()) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) "标识器${markerId}已探测".show(this) + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryLabelById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng( + bean.latitude.toDouble(), bean.longitude.toDouble() + ) + ).icon(BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1)) + ) + } + } ids.add(markerId) } } @@ -499,11 +568,11 @@ taskViewModel.loadState.observe(this) { when (it) { LoadState.Loading -> { - if (installMarkerDialog.isInstallMarker || installSmallMarkerDialog.isInstallMarker) { + if (installDialog.isInstallMarker) { LoadingDialogHub.show(this, "标识器安装中,请稍后...") } else if (searchDialog.isDetectMarker) { searchDialog.taskBean?.apply { - "标识器${this.markerId}已探测!".show(context) + "标识器${this.markerRealId}已探测!".show(context) // DataBaseManager.get.updateTaskLabel(this) } } else { @@ -512,17 +581,21 @@ } else -> { - if (installMarkerDialog.isInstallMarker) { - installMarkerDialog.dismiss() - installMarkerDialog.isInstallMarker = false - } else if (installSmallMarkerDialog.isInstallMarker) { - installSmallMarkerDialog.dismiss() - installSmallMarkerDialog.isInstallMarker = false + if (installDialog.isInstallMarker) { +// installDialog.clearDefaultData() + installDialog.dismiss() + "${installDialog.markerId}安装成功".show(context) } + + if (searchDialog.isDetectMarker) { + searchDialog.taskBean?.apply { + detectRedrawGraphic(taskId) + } + } + LoadingDialogHub.dismiss() } } - detectRedrawGraphic(taskBean.taskId) } } @@ -539,7 +612,6 @@ uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 //显示定位小蓝点 val locationStyle = MyLocationStyle() - locationStyle.interval(2000) locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) locationStyle.strokeColor(Color.argb(0, 0, 0, 0)) locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。 @@ -559,7 +631,7 @@ aMap.setOnMapLongClickListener { lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -568,9 +640,9 @@ //虽然不用显示附属标签,但是需要和标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } } @@ -579,7 +651,7 @@ } private fun moveToCurrentLocation() { - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { aMap.moveCamera( @@ -594,10 +666,10 @@ }) } -// private fun saveTaskInformation(it: TaskModel) { -// val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String -// if (it.message.size > 0) { -// it.message.forEach { messageModel -> + private fun saveTaskInformation(it: TaskModel) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + if (it.message.size > 0) { + it.message.forEach { messageModel -> // val count = DataBaseManager.get.countTaskById(messageModel.id.toString()) // if (count == 0) { // messageModel.taskDetailInfos.forEach { info -> @@ -614,19 +686,24 @@ // ) // } // } -// } -// "工单下载成功!".show(context) -// } -// } + } + "工单下载成功!".show(context) + } + } private fun showLabelsOnMap() { clusterOverlay?.onDestroy() val clusterItems = ArrayList() - labels.forEach { - val latLng = LatLng(it.latitude.toDouble(), it.longitude.toDouble(), false) - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + labelBeans.forEach { + if (it.latitude.isNotEmpty() && it.longitude.isNotEmpty()) { + val latitude = it.latitude.toDouble() + val longitude = it.longitude.toDouble() + + val latLng = LatLng(latitude, longitude, false) + val regionItem = RegionItem(latLng, it.id.toString()) + clusterItems.add(regionItem) + } } clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) @@ -703,7 +780,7 @@ override fun onActionItemClick(position: Int) { when (position) { 0 -> { - labels.forEach { + labelBeans.forEach { if (it.markerId.toString() == item.tag) { navigatePageTo(it.toJson()) } @@ -712,11 +789,11 @@ 1 -> { val electricMarkers = ArrayList() - smallLabels.forEach { - if (it.markerId.toString() == item.tag) { - electricMarkers.add(it.electricMarkerId) - } - } +// smallLabels.forEach { +// if (it.markerId.toString() == item.tag) { +// electricMarkers.add(it.electricMarkerId) +// } +// } if (electricMarkers.isEmpty()) { "此标识器没有绑定的电子标签".show(context) @@ -791,7 +868,9 @@ /** * 后台设计如此,都传companyId * */ - taskViewModel.getMarkerFile(companyId.toString(), companyId.toString()) + taskViewModel.getMarkerFile( + context, companyId.toString(), companyId.toString() + ) } else { "网络连接已断开,请检查".show(context) } @@ -803,6 +882,26 @@ }).build().show() } + //下载工单 + private fun downloadTask() { + if (isNetworkConnected()) { + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") + taskViewModel.getTask(this, userName.toString()) + } else { + "网络连接已断开,请检查".show(this) + } + } + + private fun uploadEvent() { + val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + if (taskId.isBlank()) { + "已完成全部巡检".show(this) + return + } + + navigatePageTo() + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { @@ -815,13 +914,46 @@ } else super.onKeyDown(keyCode, event) } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + //精度发生变化时触发 + } + + override fun onSensorChanged(event: SensorEvent?) { + //值发生变化时触发 + val type = event?.sensor?.type + + if (type == Sensor.TYPE_ACCELEROMETER) { + gravity = event.values + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + geomagnetic = event.values + } + + if (gravity == null || geomagnetic == null) { + return + } + + weakReferenceHandler.sendEmptyMessage(sensorMessageCode) + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == sensorMessageCode) { + if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) { + SensorManager.getOrientation(rotationMatrix, valueArray) + + val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt() +// searchNewDialog.updateDegreeValue(degree) + } + } + return true + } + /***以下是地图生命周期管理************************************************************************/ override fun onResume() { super.onResume() binding.mapView.onResume() lifecycleScope.launch { - labels = withContext(Dispatchers.IO) { + labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabels() as ArrayList } //显示标签 @@ -830,15 +962,24 @@ //虽然不用显示附属标签,但是需要喝标签做到数据同步,所以标签重新加载数据时候附属标签也需要重新加载 lifecycleScope.launch { - smallLabels = withContext(Dispatchers.IO) { - DataBaseManager.get.loadSmallLabels() as ArrayList - } +// smallLabels = withContext(Dispatchers.IO) { +// DataBaseManager.get.loadSmallLabels() as ArrayList +// } } + + //注册加速度传感器监听 + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) + + //注册磁场传感器监听 + val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) + sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() binding.mapView.onPause() + sensorManager.unregisterListener(this) } override fun onSaveInstanceState(outState: Bundle) { @@ -864,15 +1005,15 @@ private val calendar by lazy { Calendar.getInstance() } private val realPaths = ArrayList() //真实图片路径 private lateinit var imageAdapter: EditableImageAdapter + private lateinit var countDownTimer: CountDownTimer var isReadMarker = false var isInstallMarker = false + var markerId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.initDialogLayoutParams(1f) - setCancelable(false) - setCanceledOnTouchOutside(false) //初始化数据 initDefaultData() @@ -988,15 +1129,13 @@ realPaths ) - //先存本地 - lifecycleScope.launch { - withContext(Dispatchers.IO) { - DataBaseManager.get.insertLabel(labelData) - } - } + //先存本地再上传服务器 +// saveLabelInLocal() + + isInstallMarker = true //再存服务器 - taskViewModel.installLabel(labelData) +// taskViewModel.installLabel(labelData) } //读标识器 @@ -1011,14 +1150,35 @@ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f) - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() + + countDownTimer = object : CountDownTimer(5 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + soundPool.autoPause() + binding.readMarkerButton.isEnabled = true + + //降低串口电位 + gpioManager.setGpioLow("18") + + isReadMarker = false + "读取此标识器ID超时,请重试".show(context) + } + } + countDownTimer.start() } } fun bindingValue(markerId: String) { + this.markerId = markerId LoadingDialogHub.dismiss() soundPool.autoPause() + countDownTimer.cancel() binding.readMarkerButton.isEnabled = true //降低串口电位 @@ -1028,6 +1188,14 @@ binding.markerAttrInclude.markerIdView.text = markerId } + override fun dismiss() { + //降低串口电位 + gpioManager.setGpioLow("18") + soundPool.autoPause() + isInstallMarker = false + super.dismiss() + } + private fun initDefaultData() { binding.titleInclude.titleView.text = "安装新标识器" binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context)) @@ -1290,7 +1458,7 @@ binding.markerAttrInclude.installTimeView.text = System.currentTimeMillis().timestampToCompleteDate() - locationHub.getCurrentLocation(true, object : ILocationListener { + locationHub.getCurrentLocation(true, object : OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { if (location != null) { binding.markerAttrInclude.lngView.text = location.longitude.toString() @@ -1422,7 +1590,7 @@ energyTask.cancel() searchMarkerTimer.cancel() - out.write('3'.code) + out?.write('3'.code) // val result = DataBaseManager.get.queryLabelById(markerId) // if (result.isNotEmpty()) { // val tag = when (result.first().identifierType) { @@ -1605,15 +1773,15 @@ signalTask = object : TimerTask() { override fun run() { - out.write('2'.code) - out.flush() + out?.write('2'.code) + out?.flush() } } energyTask = object : TimerTask() { override fun run() { - out.write('6'.code) - out.flush() + out?.write('6'.code) + out?.flush() } } diff --git a/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt new file mode 100644 index 0000000..36e8758 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/NewObjectDetailActivity.kt @@ -0,0 +1,48 @@ +package com.casic.electric.detector.view + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import com.casic.electric.detector.databinding.ActivityNewObjectDetailBinding +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.Constant + +class NewObjectDetailActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityNewObjectDetailBinding { + return ActivityNewObjectDetailBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.3).toInt()) + window.attributes = params + + val identifierId = intent.getStringExtra(Constant.INTENT_PARAM)!! + binding.identifierIdView.text = identifierId + } + + override fun initEvent() { + binding.closeView.setOnClickListener { finish() } + binding.showImageView.setOnClickListener { + finish() + "此对象没相关照片".show(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt index 22ee740..f092eb0 100644 --- a/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/electric/detector/view/ObjectDetailActivity.kt @@ -1,23 +1,29 @@ package com.casic.electric.detector.view +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import com.casic.electric.detector.bean.LabelBean import com.casic.electric.detector.databinding.ActivityObjectDetailBinding +import com.casic.electric.detector.extensions.appendDownloadUrl +import com.casic.electric.detector.utils.FileType import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getScreenHeight import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" + private val context: Context = this@ObjectDetailActivity private val gson by lazy { Gson() } + private lateinit var labelBean: LabelBean override fun initOnCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) @@ -30,8 +36,7 @@ val objectJson = intent.getStringExtra(Constant.INTENT_PARAM)!! try { - val labelBean = - gson.fromJson(objectJson, object : TypeToken() {}.type) + labelBean = gson.fromJson(objectJson, object : TypeToken() {}.type) binding.markerObjTypeView.text = labelBean.markerObjType binding.markerNumberView.text = labelBean.markerNumber @@ -71,8 +76,29 @@ binding.closeView.setOnClickListener { finish() } binding.showImageView.setOnClickListener { - //TODO 服务器返回的表格里面并没有图片字段,此功能暂时屏蔽 - "此标识器无图片".show(this) + //查数据库 + if (labelBean.imagePath.isNullOrEmpty()) { + "此标识器无图片".show(context) + } else { + val realPaths: ArrayList = ArrayList() //真实图片路径 + + /** + * /images/markers/202307/0008818922_EVENT_20230704_160349_0_1.jpg,/images/markers/202307/0008818922_EVENT_20230704_160406_0_2.jpg + * */ + val imagePath = labelBean.imagePath + if (imagePath.contains(",")) { + val list = imagePath.split(",") + list.forEach { path -> + val url = path.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + } else { + //只有一张图片 + val url = imagePath.appendDownloadUrl(FileType.IMAGE) + realPaths.add(url) + } + navigatePageTo(0, realPaths) + } } } diff --git a/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt new file mode 100644 index 0000000..88d8640 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/view/UploadEventActivity.kt @@ -0,0 +1,170 @@ +package com.casic.electric.detector.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import androidx.lifecycle.ViewModelProvider +import com.amap.api.location.AMapLocation +import com.casic.electric.detector.adapter.EditableImageAdapter +import com.casic.electric.detector.callback.OnGetLocationListener +import com.casic.electric.detector.callback.OnImageCompressListener +import com.casic.electric.detector.databinding.ActivityUploadEventBinding +import com.casic.electric.detector.extensions.compressImage +import com.casic.electric.detector.model.EventModel +import com.casic.electric.detector.utils.LocaleConstant +import com.casic.electric.detector.utils.LocationHub +import com.casic.electric.detector.vm.TaskViewModel +import com.luck.picture.lib.basic.PictureSelector +import com.luck.picture.lib.config.SelectMimeType +import com.luck.picture.lib.entity.LocalMedia +import com.luck.picture.lib.interfaces.OnResultCallbackListener +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialogHub +import com.pengxh.kt.lite.utils.SaveKeyValues +import java.io.File + +@SuppressLint("SetTextI18n") +class UploadEventActivity : KotlinBaseActivity() { + + private val context: Context = this@UploadEventActivity + private val locationHub by lazy { LocationHub(this) } + private lateinit var imageAdapter: EditableImageAdapter + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var taskViewModel: TaskViewModel + private lateinit var taskId: String + + override fun initViewBinding(): ActivityUploadEventBinding { + return ActivityUploadEventBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + + } + + override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "事件上报中,请稍后...") + LoadState.Success -> { + LoadingDialogHub.dismiss() + "事件上报成功!".show(this) + finish() + } + + else -> LoadingDialogHub.dismiss() + } + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + window.decorView.setBackgroundColor(Color.TRANSPARENT) + window.setGravity(Gravity.CENTER) + val params = window.attributes + params.width = ((getScreenWidth() * 0.9).toInt()) + params.height = ((getScreenHeight() * 0.8).toInt()) + window.attributes = params + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String + val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String + binding.userNameView.text = userName + + binding.uploadTimeView.text = System.currentTimeMillis().timestampToCompleteDate() + + locationHub.getCurrentLocation(true, object : OnGetLocationListener { + override fun onAMapLocationGet(location: AMapLocation?) { + if (location != null) { + binding.lngView.text = "${location.longitude}" + binding.latView.text = "${location.latitude}" + } else { + "当前位置信号差,无法获取定位".show(context) + } + } + }) + + imageAdapter = EditableImageAdapter(this, 3, 3) + binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter + } + + override fun initEvent() { + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + takePicture() + } + + override fun onItemClick(position: Int) { + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + context.navigatePageTo(position, realPaths) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + imageAdapter.deleteImage(position) + } + }) + + binding.cancelButton.setOnClickListener { finish() } + + binding.uploadEventButton.setOnClickListener { + if (binding.eventDescriptionView.text.isNullOrBlank()) { + "请输入事件描述!".show(this) + return@setOnClickListener + } + + val eventModel = EventModel() + eventModel.description = binding.eventDescriptionView.text.toString() + eventModel.createTime = binding.uploadTimeView.text.toString() + + eventModel.latitude = binding.latView.text.toString().toDouble() + eventModel.longitude = binding.lngView.text.toString().toDouble() + + taskViewModel.uploadEvent(this, taskId, eventModel.toJson(), realPaths) + } + } + + private fun takePicture() { + PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) + .forResult(object : OnResultCallbackListener { + override fun onResult(result: ArrayList?) { + if (result == null) { + "拍照失败,请重试".show(context) + return + } + analyticalSelectResults(result[0]) + } + + override fun onCancel() { + + } + }) + } + + private fun analyticalSelectResults(result: LocalMedia) { + //压缩图片 + result.realPath.compressImage(this, object : OnImageCompressListener { + override fun onSuccess(file: File) { + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + }) + } + + override fun onDestroy() { + super.onDestroy() + locationHub.stopLocation() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt index 4b0bed6..ea74e8a 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/TaskViewModel.kt @@ -1,12 +1,14 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.MarkerFileModel +import com.casic.electric.detector.model.TaskModel import com.casic.electric.detector.retrofit.RetrofitServiceManager -import com.casic.electric.detector.utils.LabelDataClass +import com.casic.electric.detector.utils.DataBaseManager import com.casic.electric.detector.utils.LocaleConstant import com.casic.electric.detector.utils.SmallLabelDataClass import com.google.gson.Gson @@ -20,73 +22,129 @@ class TaskViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val markerFileResult = MutableLiveData() - - // val taskResult = MutableLiveData() + val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() val uploadTaskMarkerResult = MutableLiveData() + val executeTaskResult = MutableLiveData() - fun createFreeTask(patrollerId: String, description: String) = launch({ + fun createFreeTask(context: Context, patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ + fun uploadTaskMarker(context: Context, taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { val element = JsonParser.parseString(response) val jsonObject = element.asJsonObject uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getMarkerFile(userId: String, companyId: String) = launch({ + fun getMarkerFile(context: Context, userId: String, companyId: String) = launch({ val response = RetrofitServiceManager.getMarkerFile(userId, companyId) if (response.getResponseState()) { markerFileResult.value = gson.fromJson( response, object : TypeToken() {}.type ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun getTask(userName: String) = launch({ + fun getTask(context: Context, userName: String) = launch({ val response = RetrofitServiceManager.getTask(userName) if (response.getResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + taskResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) } else { - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() }) - fun installLabel(labelData: LabelDataClass) = launch({ + fun installLabel( + context: Context, + companyId: String, + recordType: String, + markerObjectType: String, + pipeMaterial: String, + pipeDiameter: String, + depth: String, + belowType: String, + belowMaterial: String, + belowDiameter: String, + belowDepth: String, + layStyle: String, + area: String, + line: String, + road: String, + constructTime: String, + ownerComp: String, + markerObjectId: String, + markerId: String, + markerType: String, + markerDepth: String, + creator: String, + createTime: String, + longitude: String, + latitude: String, + colorType: String, + memo: String, + realPaths: ArrayList + ) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.installLabel(labelData) + val response = RetrofitServiceManager.installLabel( + companyId, + recordType, + markerObjectType, + pipeMaterial, + pipeDiameter, + depth, + belowType, + belowMaterial, + belowDiameter, + belowDepth, + layStyle, + area, + line, + road, + constructTime, + ownerComp, + markerObjectId, + markerId, + markerType, + markerDepth, + creator, + createTime, + longitude, + latitude, + colorType, + memo, + realPaths + ) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() @@ -127,28 +185,54 @@ loadState.value = LoadState.Fail }) - fun uploadEvent(taskId: String, event: String, realPaths: ArrayList) = launch({ + fun uploadTask(context: Context, userId: String, taskId: String?, state: String) = launch({ loadState.value = LoadState.Loading - val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + val response = RetrofitServiceManager.uploadTask(userId, taskId, state) if (response.getResponseState()) { loadState.value = LoadState.Success + if (state == "2") { + "工单${taskId}已提交!".show(context) + //删除本地数据库 + DataBaseManager.get.deleteTaskById(taskId) + SaveKeyValues.putValue(LocaleConstant.TASK_ID, "") + + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + executeTaskResult.value = jsonObject.get("success").asString + } } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() loadState.value = LoadState.Fail }) - fun uploadMarker(taskDetailId: String) = launch({ + fun uploadEvent( + context: Context, taskId: String, event: String, realPaths: ArrayList + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.uploadEvent(taskId, event, realPaths) + if (response.getResponseState()) { + loadState.value = LoadState.Success + } else { + loadState.value = LoadState.Fail + response.getResponseMessage().show(context) + } + }, { + it.printStackTrace() + loadState.value = LoadState.Fail + }) + + fun uploadMarker(context: Context, taskDetailId: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.uploadMarker(taskDetailId) if (response.getResponseState()) { loadState.value = LoadState.Success } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { it.printStackTrace() diff --git a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt index ee6099b..a549290 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/UserViewModel.kt @@ -1,7 +1,7 @@ package com.casic.electric.detector.vm +import android.content.Context import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication import com.casic.electric.detector.extensions.getResponseMessage import com.casic.electric.detector.extensions.getResponseState import com.casic.electric.detector.model.LoginResultModel @@ -19,10 +19,9 @@ * */ class UserViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val loginResult = MutableLiveData() - fun login(account: String, password: String) = launch({ + fun login(context: Context, account: String, password: String) = launch({ loadState.value = LoadState.Loading val response = RetrofitServiceManager.login(account, password) if (response.getResponseState()) { @@ -32,14 +31,15 @@ ) } else { loadState.value = LoadState.Fail - response.getResponseMessage().show(BaseApplication.get()) + response.getResponseMessage().show(context) } }, { + it.printStackTrace() loadState.value = LoadState.Fail - if (BaseApplication.get().isNetworkConnected()) { - "连接服务器失败,IP或端口错误".show(BaseApplication.get()) + if (context.isNetworkConnected()) { + "连接服务器失败,IP或端口错误".show(context) } else { - "网络连接失败".show(BaseApplication.get()) + "网络连接失败".show(context) } }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt index b488b5b..0d31329 100644 --- a/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt +++ b/app/src/main/java/com/casic/electric/detector/vm/VersionViewModel.kt @@ -1,20 +1,16 @@ package com.casic.electric.detector.vm import androidx.lifecycle.MutableLiveData -import com.casic.electric.detector.base.BaseApplication -import com.casic.electric.detector.extensions.convertChinese import com.casic.electric.detector.model.VersionResultModel import com.casic.electric.detector.retrofit.RetrofitServiceManager import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.base.BaseViewModel import com.pengxh.kt.lite.extensions.launch -import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.LoadState class VersionViewModel : BaseViewModel() { private val gson by lazy { Gson() } - val versionResult = MutableLiveData() fun getApplicationVersion() = launch({ @@ -25,7 +21,7 @@ ) loadState.value = LoadState.Success }, { + it.printStackTrace() loadState.value = LoadState.Fail - it.convertChinese().show(BaseApplication.get()) }) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..372d973 --- /dev/null +++ b/app/src/main/java/com/casic/electric/detector/widgets/RadarScanView.kt @@ -0,0 +1,414 @@ +package com.casic.electric.detector.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PointF +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.SweepGradient +import android.graphics.Typeface +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.electric.detector.R +import com.casic.electric.detector.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //外圆文字路径半径 + private var outerRadius: Int + + //控件边长 + private val viewSideLength: Int + private val rect: Rect + + //需要渲染的数据点集合 + private var points: ArrayList? = null + + //距离最近的点 + private var targetPoint: PointF? = null + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + //方位角 + private var degreeValue = 0 + + private lateinit var tickPaint: Paint + private lateinit var backPaint: Paint + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + private lateinit var outerPaint: TextPaint + private lateinit var outerTextPath: Path + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //背景栅格图 + private lateinit var bitmap: Bitmap + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + //背景区域范围 + private var bgRect: Rect + + //刻度长度 + private val tickLength = 15f.dp2px(context) + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor( + R.styleable.RadarScanView_radar_borderColor, Color.parseColor("#8000FFF0") + ) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 300) + type.recycle() + + outerRadius = radius + 8.dp2px(context) + + //需要给外围刻度留位置 + viewSideLength = radius + 30.dp2px(context) + //辅助框 + rect = Rect(-viewSideLength, -viewSideLength, viewSideLength, viewSideLength) + + bgRect = Rect(-radius, -radius, radius, radius) + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + tickPaint = Paint() + tickPaint.color = Color.RED + tickPaint.style = Paint.Style.STROKE + tickPaint.strokeWidth = 2f.dp2px(context) + tickPaint.isAntiAlias = true + + backPaint = Paint() + backPaint.isAntiAlias = true + bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.bg_radar) + + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + outerPaint = TextPaint() + outerPaint.isAntiAlias = true + outerPaint.textAlign = Paint.Align.CENTER + outerPaint.textSize = 14f.sp2px(context) + outerTextPath = Path() + val innerRectF = RectF( + -outerRadius.toFloat(), + -outerRadius.toFloat(), + outerRadius.toFloat(), + outerRadius.toFloat() + ) + outerTextPath.addArc(innerRectF, -90f, 360f) + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = Color.RED + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec) + val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) + // 获取宽 + val mWidth: Int = if (widthSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + widthSpecSize + } else { + // wrap_content,外边界宽 + (viewSideLength * 2) + } + // 获取高 + val mHeight: Int = if (heightSpecMode == MeasureSpec.EXACTLY) { + // match_parent/精确值 + heightSpecSize + } else { + // wrap_content,外边界高 + (viewSideLength * 2) + } + // 设置该view的宽高 + setMeasuredDimension(mWidth, mHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + + //画最外层圆环 + canvas.drawCircle(0f, 0f, (radius + tickLength), borderPaint) + + //画背景 + canvas.drawBitmap(bitmap, null, bgRect, backPaint) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画方位 + for (angle in 0 until 360 step 90) { + //角度需要转为弧度 + val radians = (angle - 180) * (Math.PI / 180) + + val hOffset = outerRadius * radians + + var direction = "" + when (angle) { + 0 -> { + direction = "北" + outerPaint.color = Color.RED + outerPaint.typeface = Typeface.DEFAULT_BOLD + } + + 90 -> { + direction = "东" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 180 -> { + direction = "南" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + + 270 -> { + direction = "西" + outerPaint.color = Color.WHITE + outerPaint.typeface = Typeface.DEFAULT + } + } + + val fontMetrics = outerPaint.fontMetrics + val top = fontMetrics.top //基线到字体上边框的距离,即上图中的top + val bottom = fontMetrics.bottom //基线到字体下边框的距离,即上图中的bottom + val fontHeight = top + bottom + canvas.drawTextOnPath( + direction, + outerTextPath, + hOffset.toFloat(), + -fontHeight / 2, + outerPaint + ) + } + + //画实时方位角 + if (degreeValue < 180) { + for (angle in 0..degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.strokeWidth = 8f.dp2px(context) + tickPaint.color = borderColor + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } else { + for (angle in 360 downTo degreeValue step 3) { + //角度需要转为弧度 + val radians = (angle - 90) * (Math.PI / 180) + + val startX = (radius + tickLength) * cos(radians) + val startY = (radius + tickLength) * sin(radians) + + val stopX = radius * cos(radians) + val stopY = radius * sin(radians) + + tickPaint.color = borderColor + tickPaint.strokeWidth = 8f.dp2px(context) + canvas.drawLine( + startX.toFloat(), + startY.toFloat(), + stopX.toFloat(), + stopY.toFloat(), + tickPaint + ) + } + } + + //画数据点 + points?.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //画最近的点最外层圆环 + targetPoint?.apply { + canvas.drawCircle(x, y, 12f, borderPaint) + } + + /** + * 上下翻转画布,否则矩阵旋转是逆时针,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 更新罗盘方位角度 + * @param value 方位角 + * */ + fun setDegreeValue(value: Int) { + degreeValue = value + //实时刷新角度值 + invalidate() + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * @param callback 最小值的点 + * */ + fun renderPointData(dataPoints: ArrayList, callback: OnGetNearestPointCallback) { + if (dataPoints.isNotEmpty()) { + points = ArrayList() + dataPoints.forEach { + points?.add(it.convertPointF()) + } + + //计算出附近最近的点 + dataPoints.sortBy(DataPoint::distance) + + val nearestPoint = dataPoints.first() + //减少排序计算次数,回调最近的点到主界面 + callback.getNearestPoint(nearestPoint) + + //在最近的点外侧绘制同心圆 + targetPoint = nearestPoint.convertPointF() + } else { + points?.clear() + targetPoint = null + callback.getNearestPoint(null) + } + //不管有无数据点,都要刷新点位数据,不然从有数据到无数据这个过程,界面不会及时刷新 + invalidate() + } + + interface OnGetNearestPointCallback { + fun getNearestPoint(point: DataPoint?) + } + + /** + * dataPoint转为PointF + * */ + private fun DataPoint.convertPointF(): PointF { + val dataAngle = (this.angle * Math.PI / 180).toFloat() + + /** + * 距离最大5.5米,表盘四个环,一个环距离1.5米,半径124dp(248px) + * */ + val dataDistance = (this.distance / LocaleConstant.MAX_DISTANCE) * radius + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + return PointF(x, y) + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(var angle: Int, var distance: Float) +} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk deleted file mode 100644 index 94bf9d0..0000000 --- a/app/src/main/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Android.mk必须以LOCAL_PATH开头,注释#除外 -# 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 -LOCAL_PATH := $(call my-dir) - -# 借助CLEAR_VARS变量清除除LOCAL_PATH外的所有LOCAL_变量 -include $(CLEAR_VARS) - -# android-3 对应Android 1.5 -TARGET_PLATFORM := android-3 - -# 设置模块的名称,即编译出来.so文件名 -# 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 -LOCAL_MODULE := serial_port - -# 指定参与模块编译的C/C++源文件列表,多文件用"\"隔开 -LOCAL_SRC_FILES := SerialPort.c - -LOCAL_LDLIBS := -llog - -# 必须在文件结尾定义编译类型,指定生成的静态库或者共享库在运行时依赖的共享库模块列表。 -# BUILD_SHARED_LIBRARY 共享库,供java或者其他共享库调用 -# BUILD_STATIC_LIBRARY 静态库,供共享库调用,不能直接被java调用 -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/app/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/app/src/main/jni/SerialPort.c b/app/src/main/jni/SerialPort.c deleted file mode 100644 index b9fcfcd..0000000 --- a/app/src/main/jni/SerialPort.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// Created by 203 on 2023/8/15. -// -#include -#include -#include -#include -#include -#include -#include - -#include "SerialPort.h" - -#include "android/log.h" - -static const char *TAG = "serial_port"; -#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) -#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) - -static speed_t getBaudRate(jint baudRate) { - switch (baudRate) { - case 0: - return B0; - case 50: - return B50; - case 75: - return B75; - case 110: - return B110; - case 134: - return B134; - case 150: - return B150; - case 200: - return B200; - case 300: - return B300; - case 600: - return B600; - case 1200: - return B1200; - case 1800: - return B1800; - case 2400: - return B2400; - case 4800: - return B4800; - case 9600: - return B9600; - case 19200: - return B19200; - case 38400: - return B38400; - case 57600: - return B57600; - case 115200: - return B115200; - case 230400: - return B230400; - case 460800: - return B460800; - case 500000: - return B500000; - case 576000: - return B576000; - case 921600: - return B921600; - case 1000000: - return B1000000; - case 1152000: - return B1152000; - case 1500000: - return B1500000; - case 2000000: - return B2000000; - case 2500000: - return B2500000; - case 3000000: - return B3000000; - case 3500000: - return B3500000; - case 4000000: - return B4000000; - default: - return -1; - } -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL -Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jclass thiz, jstring path, jint baudRate, - jint flags) { - int fd; - speed_t speed; - jobject mFileDescriptor; - - /* Check arguments */ - { - speed = getBaudRate(baudRate); - if (speed == -1) { - LOGE("Invalid baudRate"); - return NULL; - } - } - - /* Opening device */ - { - jboolean iscopy; - const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); - LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); - fd = open(path_utf, O_RDWR | flags); - LOGD("open() fd = %d", fd); - (*env)->ReleaseStringUTFChars(env, path, path_utf); - if (fd == -1) { - LOGE("Cannot open port"); - return NULL; - } - } - - /* Configure device */ - { - struct termios cfg; - LOGD("Configuring serial port"); - if (tcgetattr(fd, &cfg)) { - LOGE("tcgetattr() failed"); - close(fd); - return NULL; - } - - cfmakeraw(&cfg); - cfsetispeed(&cfg, speed); - cfsetospeed(&cfg, speed); - - if (tcsetattr(fd, TCSANOW, &cfg)) { - LOGE("tcsetattr() failed"); - close(fd); - return NULL; - } - } - - /* Create a corresponding file descriptor */ - { - jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); - jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); - jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); - mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); - (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd); - } - - return mFileDescriptor; -} - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) { - jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); - jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); - - jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); - jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); - - jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); - jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); - - LOGD("close(fd = %d)", descriptor); - close(descriptor); -} diff --git a/app/src/main/jni/SerialPort.h b/app/src/main/jni/SerialPort.h deleted file mode 100644 index c29cb12..0000000 --- a/app/src/main/jni/SerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_casic_electric_detector_uart_SerialPort */ - -#ifndef _Included_com_casic_electric_detector_uart_SerialPort -#define _Included_com_casic_electric_detector_uart_SerialPort -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: open - * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; - */ -JNIEXPORT jobject JNICALL Java_com_casic_electric_detector_uart_SerialPort_open - (JNIEnv *, jclass, jstring, jint, jint); - -/* - * Class: com_casic_electric_detector_uart_SerialPort - * Method: close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_casic_electric_detector_uart_SerialPort_close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/app/src/main/jni/gen_SerialPort_h.sh b/app/src/main/jni/gen_SerialPort_h.sh deleted file mode 100755 index b67dae6..0000000 --- a/app/src/main/jni/gen_SerialPort_h.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -javah -encoding utf-8 -o SerialPort.h -jni -classpath ../java com.casic.electric.detector.uart.SerialPort - diff --git a/app/src/main/jniLibs/arm64-v8a/libserial_port.so b/app/src/main/jniLibs/arm64-v8a/libserial_port.so deleted file mode 100755 index 113944a..0000000 --- a/app/src/main/jniLibs/arm64-v8a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so b/app/src/main/jniLibs/armeabi-v7a/libserial_port.so deleted file mode 100755 index 265880a..0000000 --- a/app/src/main/jniLibs/armeabi-v7a/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86/libserial_port.so b/app/src/main/jniLibs/x86/libserial_port.so deleted file mode 100755 index 47e985a..0000000 --- a/app/src/main/jniLibs/x86/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/jniLibs/x86_64/libserial_port.so b/app/src/main/jniLibs/x86_64/libserial_port.so deleted file mode 100755 index 558eb36..0000000 --- a/app/src/main/jniLibs/x86_64/libserial_port.so +++ /dev/null Binary files differ diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml index 228c2c4..b0b948c 100644 --- a/app/src/main/res/layout/activity_big_image.xml +++ b/app/src/main/res/layout/activity_big_image.xml @@ -26,7 +26,7 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="@dimen/lib_dp_10" - android:src="@drawable/ic_left_white" /> + android:src="@drawable/ic_title_left" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_upload_event.xml b/app/src/main/res/layout/activity_upload_event.xml new file mode 100644 index 0000000..cce69c1 --- /dev/null +++ b/app/src/main/res/layout/activity_upload_event.xml @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +