Explorar o código

第一次上传

xunchuanzhi hai 11 meses
achega
5da0720b68
Modificáronse 100 ficheiros con 26645 adicións e 0 borrados
  1. 11 0
      .gitignore
  2. 68 0
      README.md
  3. 1 0
      android_bed/.gitignore
  4. 224 0
      android_bed/build.gradle
  5. BIN=BIN
      android_bed/libs/xbh-sdk-release-v4.0.0.383-20240319.jar
  6. BIN=BIN
      android_bed/libs/zhylapi.jar
  7. 21 0
      android_bed/proguard-rules.pro
  8. 110 0
      android_bed/src/main/AndroidManifest.xml
  9. BIN=BIN
      android_bed/src/main/assets/launch.apk
  10. BIN=BIN
      android_bed/src/main/assets/wd_update_plugin.apk
  11. 1 0
      android_bed/src/main/assets/web/echarts/echarts.js.map
  12. 45 0
      android_bed/src/main/assets/web/echarts/echarts.min.js
  13. BIN=BIN
      android_bed/src/main/assets/web/res/element-icons.woff
  14. 1 0
      android_bed/src/main/assets/web/res/index.css
  15. 1 0
      android_bed/src/main/assets/web/res/index.js
  16. 7 0
      android_bed/src/main/assets/web/res/vue-resource.min.js
  17. 12014 0
      android_bed/src/main/assets/web/res/vue.js
  18. 286 0
      android_bed/src/main/assets/web/vital_sign_log.html
  19. 257 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/AppUpdateActivity.kt
  20. 458 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivationActivity.kt
  21. 937 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivity.kt
  22. 379 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/DeviceLinkageActivity.kt
  23. 226 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/DeviceSystemActivity.kt
  24. 277 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/SleepMonitoringActivity.kt
  25. 366 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/SystemActivity.kt
  26. 184 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/WebviewActivity.kt
  27. 99 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/DeviceLinAdapter.kt
  28. 56 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/NumAdapter.java
  29. 77 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/NurseConfigAdpter.kt
  30. 12 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/agreement/CallingbedAgreement.kt
  31. 30 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/broadcast/ScreenBroadcastReceiver.java
  32. 26 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/broadcast/WdBootReceiver.java
  33. 13 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BTConstants.java
  34. 368 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BaxcSocketConnect.java
  35. 369 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BaxcSocketConnectLine.java
  36. 506 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BluetoothService.java
  37. 156 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BluetoothUtil.java
  38. 133 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/DataParse.java
  39. 38 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/Device.java
  40. 143 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/NotificationUtil.java
  41. 20 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/SignData.java
  42. 80 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/SocketConnect.java
  43. 39 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/di/CallingbedComponent.kt
  44. 112 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/CallConfigDialogHelper.java
  45. 115 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/DeviceLinkDialogHelper.java
  46. 98 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/DeviceLinkSleepDialogHelper.java
  47. 113 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/Network2DialogHelper.java
  48. 105 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/NetworkDialogHelper.java
  49. 64 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/RebootDialogHelper.java
  50. 75 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/ReinforcementsDialogHelper.java
  51. 94 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/ServicesDialogHelper.java
  52. 111 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/SystemDialogHelper.java
  53. 71 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/UpdataDialogHelper.java
  54. 79 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/WifiSetDialogHelper.java
  55. 255 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/MainFragment.kt
  56. 365 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/SleepDataTableFragment.kt
  57. 255 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/SleepGraphOfCurveFragment.kt
  58. 335 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/apartmentFragment.kt
  59. 65 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/HardTools.java
  60. 25 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/HardWareFactory.java
  61. 186 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/imp/LGCBDHardTools.java
  62. 14 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AlarmMessageUtil.java
  63. 252 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AnrFcExceptionUtil.java.bak
  64. 305 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AppUpdateHelper.java
  65. 121 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AppUtil.java
  66. 187 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AsyncPlayer.java
  67. 83 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/CallDialogHelper.java
  68. 24 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/CommonDialogHelper.java
  69. 19 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/DoorLightHelper.java
  70. 189 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/HttpHelper.java
  71. 83 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ImPlayDialogHelper.java
  72. 61 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/KaerStatsBarHelper.java
  73. 145 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/LanguageSetDialogHelper.java
  74. 242 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/MediaPlayHelper.java
  75. 729 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/NetHelper.java
  76. 128 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/PasswordDialogHelper.java
  77. 126 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/RecordHelper.java
  78. 58 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SOSHelper.java
  79. 81 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ScreenManagerUtil.kt
  80. 62 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SerialPortHelper.java
  81. 159 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ServerConfigDialogHelper.java
  82. 85 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SoundPoolManager.java
  83. 197 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SpeechUtil.java
  84. 101 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/UpdateTipsDialogHelper.java
  85. 68 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/Util.kt
  86. 110 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/Utils.java
  87. 188 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/VoiceManagerUtil.java
  88. 57 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/WarningDialogHelper.java
  89. 248 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/XCrashUtils.java
  90. 20 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/launch/CallingbedLaunch.kt
  91. 64 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/service/ViewService.java
  92. 509 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/settings/SettingConfig.java
  93. 148 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepDataParse.java
  94. 59 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepLoginDataParse.java
  95. 546 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepService.java
  96. 59 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSetwifiDataParse.java
  97. 80 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSocketConnect.java
  98. 417 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSocketConnectLine.java
  99. 59 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/cdb/BedLoginDataParse.java
  100. 0 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/cdb/CbdBedDataParse.java

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+*.iml
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+/gradle
+.externalNativeBuild
+/.gradle
+/.idea

+ 68 - 0
README.md

@@ -0,0 +1,68 @@
+#更新日志
+格式化请点击参考 [学习链接](https://keepachangelog.com/en/1.0.0/)
+版本号规范请参考 [学习链接](https://semver.org/spec/v2.0.0.html)
+## 指导原则
+- 记住日志是写给人的,而非机器。
+- 每个版本都应该有独立的入口。
+- 同类改动应该分组放置。
+- 版本与章节应该相互对应。
+- 新版本在前,旧版本在后。
+- 应包括每个版本的发布日期。
+- 注明是否遵守语义化版本格式.
+## 变动类型
+- Added 新添加的功能。
+- Changed 对现有功能的变更。
+- Deprecated 已经不建议使用,准备很快移除的功能。
+- Removed 已经移除的功能。
+- Fixed 对bug的修复
+- Security 对安全的改进
+## [Unreleased]
+此区块记录即将发布的更新内容。
+
+两大意义:
+
+大家可以知道在未来版本中可能会有哪些变更
+在发布新版本时,可以直接将Unreleased区块中的内容移动至新发 布版本的描述区块就可以了
+
+
+
+##########################################################
+#################    janus信令版本    ####################
+##########################################################
+
+## [1.1.13] version 13
+### CHANGE
+- 兼容新豪格10寸竖屏设备
+
+## [1.1.11] version 11
+### CHANGE
+- 语音通话切换切换到janus信令
+- 修改夜晚模式下紧急按钮灯常亮
+- 护理状态门灯演示支持服务端定义
+- 增加手动配置服务器地址
+
+
+
+
+##########################################################
+---
+## [1.0.5] version 5 - 2021-12-25
+### CHANGE
+- 修改tcp数据长度及设备连接信息
+- 增加责任医生责任护士显示
+- 禁用activity滑动退出
+- 增加服务器时间同步
+
+## [1.0.3] version 3 - 2021-11-17
+### CHANGE
+- 兼容rk3288豪格15.6寸竖屏设备
+- 增加护理控制
+- 增加呼叫主机和呼叫分机功能
+- 优化护理状态显示
+- 15.6寸设备使用序列号注册,保持屏幕常亮
+- app升级功能优化
+- 增加隐藏功能:连续点击8次右下角版本号进入系统设置
+
+
+
+### 门口机医院版本,基于ncs_callingbed2创建

+ 1 - 0
android_bed/.gitignore

@@ -0,0 +1 @@
+/build

+ 224 - 0
android_bed/build.gradle

@@ -0,0 +1,224 @@
+
+if (rootProject.ext.android_bed.toBoolean()) {
+    apply plugin: 'com.android.library'
+} else {
+    return
+}
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+
+kapt {
+    arguments {
+        arg("moduleName", project.getName())
+    }
+}
+
+android {
+    compileSdkVersion target_sdk_version
+    buildToolsVersion build_tools_version
+    defaultConfig {
+        minSdkVersion min_sdk_version
+        targetSdkVersion target_sdk_version
+        versionCode app_version_code
+        versionName app_version
+        flavorDimensions "app"
+        multiDexEnabled true
+        buildFeatures {
+            dataBinding = true
+        }
+        buildConfigField "String", "BUILD_TIME", getDate()
+        buildConfigField 'String', 'VERSION_NAME', "\"${project.rootProject.ext.app_version}\""
+        buildConfigField 'String', 'VERSION_CODE', "\"${project.rootProject.ext.app_version_code}\""
+        buildConfigField 'String', 'iscallingdoor', "\"${project.rootProject.ext.callingdoor}\""
+        buildConfigField 'String', 'isandroid_bed', "\"${project.rootProject.ext.android_bed}\""
+        buildConfigField 'String', 'isandroid_host', "\"${project.rootProject.ext.android_host}\""
+        buildConfigField 'String', 'isandroid_mobile', "\"${project.rootProject.ext.android_mobile}\""
+        buildConfigField 'String', 'isandroid_visiting', "\"${project.rootProject.ext.android_visiting}\""
+        buildConfigField 'String', 'is_mom', "\"${project.rootProject.ext.is_mom}\""
+        buildConfigField 'String', 'open_sleep', "\"${project.rootProject.ext.open_sleep}\""
+        buildConfigField 'String', 'open_433', "\"${project.rootProject.ext.open_433}\""
+        buildConfigField 'String', 'device_type', "\"${project.rootProject.ext.device_type}\""
+        buildConfigField 'String', 'sleep_type', "\"${project.rootProject.ext.sleep_type}\""
+        buildConfigField 'String', 'cbd_type', "\"${project.rootProject.ext.cbd_type}\""
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    productFlavors {
+        rk3128 {//自研
+            dimension "app"
+            buildConfigField 'String', 'flag', '"1"'
+        }
+
+        xhg_rk3288 {//自研
+            dimension "app"
+            buildConfigField 'String', 'flag', '"2"'
+        }
+        //外购 大朝华7寸
+        dch_7 {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"4"'
+        }
+
+        //亿莱顿可视分机
+        yld {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"5"'
+        }
+        //卡尔-护士主机
+        kaer {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"6"'
+        }
+        //外购 a133s
+        zhihe_A133 {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"7"'
+        }
+        //中兴8寸
+        zx_8 {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"8"'
+        }
+        //普威10寸
+        pw_10 {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"10"'
+        }
+        //朗国
+        langguo {
+            dimension "app"
+            buildConfigField 'String', 'flag', '"11"'
+        }
+    }
+    sourceSets {
+        main.java.srcDirs += 'src/main/code'
+
+        rk3128 {//自研
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+
+        xhg_rk3288 {//自研
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+        //外购 大朝华7寸
+        dch_7 {
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+
+        //亿莱顿可视分机
+        yld {
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+
+        //中兴8寸
+        zx_8 {
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+
+        //普威10
+        pw_10 {
+            manifest.srcFile 'src/main/AndroidManifest.xml'
+        }
+
+        //卡尔主机
+        kaer {
+            manifest.srcFile 'src/main/sharedUserId/AndroidManifest.xml'
+        }
+
+
+
+    }
+    lintOptions {
+        abortOnError false
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+}
+
+//获取编译日期
+String getDate() {
+    Date date = new Date();
+    String dates = "\""+date.format("yyyy/MM/dd", TimeZone.getTimeZone("UTC"))+"\""
+    return dates
+}
+
+dependencies {
+    implementation files('libs/xbh-sdk-release-v4.0.0.383-20240319.jar')
+    implementation files('libs/zhylapi.jar')
+
+    /**
+     * 单元测试
+     */
+    testImplementation 'junit:junit:4.12'
+
+
+
+    /**
+     * 公共库依赖
+     */
+    implementation project(':welcome')
+    implementation project(':middleware')
+    implementation project(':bedlib')
+    //janus信令
+    implementation project(':janus')
+
+    /**
+     * Dagger编译依赖
+     */
+    kapt 'com.google.dagger:dagger-compiler:2.7'
+
+    /**
+     * Kotlin依赖
+     */
+    kapt 'com.android.databinding:compiler:2.3.3'
+
+    /**
+     * 路由注解处理器
+     */
+    kapt "com.enation.geamtear:jrouter-compiler:$router_version"
+
+    /**
+     *  constraint-layout布局依赖
+     */
+    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+
+    //compile 'com.github.anrwatchdog:anrwatchdog:1.3.0'
+
+    //使用xCrash捕获异常
+    implementation 'com.iqiyi.xcrash:xcrash-android-lib:3.0.0'
+
+    //蓝牙
+    implementation 'com.clj.fastble:FastBleLib:2.3.4'
+    implementation 'org.altbeacon:android-beacon-library:2.17'
+
+//    implementation 'com.github.AAChartModel:AAChartCore-Kotlin:-SNAPSHOT'
+
+    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
+
+    compile 'com.inuker.bluetooth:library:1.4.0'
+
+}
+
+/**
+ * kawo组件化框架配置
+ */
+if(componentTag){
+    kawo {
+        /**
+         * Aop注解排除Jar
+         */
+        aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
+    }
+}

BIN=BIN
android_bed/libs/xbh-sdk-release-v4.0.0.383-20240319.jar


BIN=BIN
android_bed/libs/zhylapi.jar


+ 21 - 0
android_bed/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 110 - 0
android_bed/src/main/AndroidManifest.xml

@@ -0,0 +1,110 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.wdkl.app.ncs.callingbed">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
+    <uses-permission android:name="android.intent.action.SET_TIME" />
+    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
+    <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <!-- 如果设配Android9及更低版本,可以申请 ACCESS_COARSE_LOCATION -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
+
+    <uses-feature
+        android:name="android.hardware.nfc"
+        android:required="false" />
+
+    <application
+        android:hardwareAccelerated="false"
+        android:largeHeap="true"
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:supportsRtl="true" >
+
+        <meta-data
+            android:name="com.enation.javashop.imagepluin.cache.MyGlideModule"
+            android:value="GlideModule" />
+        <meta-data
+            android:name="design_width_in_dp"
+            android:value="1024"/>
+        <meta-data
+            android:name="design_height_in_dp"
+            android:value="600"/>
+        <meta-data
+            android:name="com.google.android.actions"
+            android:resource="@xml/nfc_tech" />
+
+
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.CallingbedActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask" >
+        </activity>
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.CallingbedActivationActivity"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.SystemActivity"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.AppUpdateActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.WebviewActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.SleepMonitoringActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.DeviceSystemActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+
+        <activity android:name="com.wdkl.app.ncs.callingbed.activity.DeviceLinkageActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:launchMode="singleTask"/>
+
+
+        <service android:name="com.wdkl.app.ncs.callingbed.sleep.SleepService"/>
+
+        <service   android:name="com.wdkl.app.ncs.callingbed.service.ViewService"/>
+
+        <receiver
+            android:name="com.wdkl.app.ncs.callingbed.broadcast.WdBootReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter android:priority="1000">
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="com.wdkl.app.ncs.callingbed.broadcast.ScreenBroadcastReceiver">
+            <intent-filter >
+                <action android:name="com.wdkl.voip.Receivers"/>
+            </intent-filter>
+        </receiver>
+
+    </application>
+</manifest>

BIN=BIN
android_bed/src/main/assets/launch.apk


BIN=BIN
android_bed/src/main/assets/wd_update_plugin.apk


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
android_bed/src/main/assets/web/echarts/echarts.js.map


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 45 - 0
android_bed/src/main/assets/web/echarts/echarts.min.js


BIN=BIN
android_bed/src/main/assets/web/res/element-icons.woff


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
android_bed/src/main/assets/web/res/index.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
android_bed/src/main/assets/web/res/index.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
android_bed/src/main/assets/web/res/vue-resource.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 12014 - 0
android_bed/src/main/assets/web/res/vue.js


+ 286 - 0
android_bed/src/main/assets/web/vital_sign_log.html

@@ -0,0 +1,286 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="UTF-8">
+    <link rel="stylesheet" href="res/index.css">
+    <script src="res/vue.js"></script>
+    <script src="res/vue-resource.min.js"></script>
+    <script src="res/index.js"></script>
+</head>
+
+<body>
+<div id="app">
+    <el-tabs v-model="activeName" type="border-card" @tab-click="tabChange">
+        <el-tab-pane v-for="group in vitalSignsLogs" :key="group.id" :label="group.vital_signs_name" :name="'vital_signs'+group.id" :data="group.id">
+            <div :id="`chart${group.id}`" :style="'height: 600px; width:'+screenWidth+'px'"></div>
+        </el-tab-pane>
+    </el-tabs>
+
+    <div>
+
+        <el-table
+                v-loading="tableLoading"
+                stripe
+                :data="tableData"
+                style="width: 100%">
+            <el-table-column prop="log_time" label="测量时间" min-width="180">
+                <template slot-scope="scope">
+                    <i class="el-icon-time"></i>
+                    <span style="margin-left: 5px">{{ unixToDate(scope.row.log_time,'yyyy-MM-dd hh:mm:ss')}}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="param_name" label="体征参数" min-width="160">
+                <template slot-scope="scope">
+                    <span>{{scope.row.group_name===scope.row.param_name?scope.row.param_name:scope.row.group_name+'-'+scope.row.param_name}}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="vs_value" label="体征值" min-width="120"></el-table-column>
+        </el-table>
+
+        <!--翻页-->
+        <el-pagination
+                v-if="pageData"
+                :current-page="pageData.page_no"
+                layout="prev, pager, next"
+                @current-change="handlePageCurrentChange"
+                :total="pageData.data_total">
+        </el-pagination>
+    </div>
+</div>
+<script src="echarts/echarts.min.js"></script>
+<script type="application/javascript">
+    new Vue({
+        el: '#app',
+        data: function () {
+            return {
+                gateWay: "http://119.23.151.229:5005",
+                vitalSignsLogs: {},
+                /** 图表颜色集合 */
+                colors: ['#5793f3', '#d14a61', '#675bba', '#660099', '#7e0023'],
+                params: {
+                    page_no: 1,
+                    page_size: 10
+                },
+                activeName: "vital_signs1",
+                tableData: [],
+                pageData: [],
+                groupId: 1,
+                memberId: null,
+                screenWidth: document.body.clientWidth,
+                tableLoading:true
+            }
+        },
+        mounted() {
+            this.memberId = this.getQueryString("id");
+            this.gateWay = this.getQueryString("gw");
+            this.GET_LogListPage();
+            this.GET_VitalSingsGroupParamLogs();
+            window.refreshData = this.refreshData
+        },
+        methods:{
+            refreshData:function(){
+                this.GET_LogListPage();
+                this.GET_VitalSingsGroupParamLogs();
+            },
+            tabChange(tab){
+                this.groupId = tab.$attrs.data
+                this.GET_LogListPage()
+            },
+            getQueryString:function(name) {
+                var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
+                var r = window.location.search.substr(1).match(reg);
+                if (r != null) {
+                    return unescape(r[2]);
+                }
+                return null;
+            },
+            unixToDate(unix, format) {
+                const d = new Date(unix * 1000).toLocaleString()
+                return d;
+            },
+            handlePageCurrentChange(page) {
+                this.params.page_no = page
+                this.GET_LogListPage()
+            },
+            /** 查询体征日志 */
+            GET_LogListPage:function() {
+                var _this = this;
+                var params = {
+                    page_no: this.params.page_no,
+                    page_size: this.params.page_size,
+                    sort: 'log_time',
+                    dir: 'desc',
+                    groupid: this.groupId,
+                    memberid: this.memberId
+                }
+                this.$http.post(this.gateWay + "/care/care_vital_signs_log/page",params,{emulateJSON:true}).then(function(res){
+                    _this.tableLoading = false;
+                    _this.tableData=res.body.data;
+                    _this.pageData = {
+                        page_no: res.body.page_no,
+                        page_size: res.body.page_size,
+                        data_total: res.body.data_total
+                    }
+                },function(){
+                    _this.tableLoading = false;
+                    console.log("请求失败处理");
+                });
+            },
+
+            MixinClone(obj) {
+                return JSON.parse(JSON.stringify(obj))
+            },
+            //统计图
+            GET_VitalSingsGroupParamLogs:function() {
+                const loading = this.$loading({
+                  lock: true,
+                  text: '加载图表中',
+                  spinner: 'el-icon-loading',
+                  background: 'rgba(0, 0, 0, 0.7)'
+                });
+                this.$http.get(this.gateWay + `/care/vitalsignsgroup/log/${this.memberId}`).then(function(response){
+                    console.log(response.body)
+                    this.vitalSignsLogs = response.body
+                    const option = {// 图表选项option对象
+                        color: this.colors, // 颜色集合
+                        title: {
+                            text: '',
+                            x: 'center',
+                            align: 'right'
+                        },
+                        tooltip: {
+                            trigger: 'none',
+                            axisPointer: {
+                                type: 'cross'
+                            }
+                        }, // 图表提示
+
+                        dataZoom: [],
+
+                        legend: {
+                            top: 30,
+                            data: []
+                        },
+                        grid: {
+                            top: 90,
+                            bottom: 150
+                        }, // 图表表格位置
+                        yAxis: [
+                            {
+                                type: 'value'
+                            }
+                        ], // Y轴设置
+                        xAxis: [], // X轴集合
+                        series: []// 值数据集合
+                    }
+                    const xAxi = { // x轴对象
+                        type: 'category',
+                        axisTick: {
+                            alignWithLabel: true
+                        },
+                        axisLine: {
+                            onZero: false,
+                            lineStyle: {
+                                color: this.colors[1]
+                            }
+                        },
+                        nameLocation: 'middle',
+                        offset: 25,
+                        position: 'bottom',
+                        axisPointer: {
+
+                            label: {
+                                formatter: function(params) {
+
+                                }
+                            }
+                        },
+                        data: []
+                    }
+                    const serie = { // 值对象
+
+                        name: '',
+                        type: 'line',
+                        xAxisIndex: 0,
+                        smooth: true,
+                        data: [],
+                        markLine: {
+                            silent: true,
+                            data: []
+                        }
+
+                    }
+                    const zoomitem =
+                        {
+                            show: true,
+                            type: 'slider',
+                            realtime: true,
+                            start: 90,
+                            end: 100,
+                            xAxisIndex: []
+                        }
+
+                    // 构建图表X轴集合和值集合
+                    this.vitalSignsLogs.forEach((key, ix) => {
+                        if (key && key.paramlogs) {
+                            const op = this.MixinClone(option)
+                            const legenddata = [] // 图例集合
+                            const zoom = this.MixinClone(zoomitem)
+
+                            op.title.text = key.vital_signs_name + '体征参数'
+
+                            key.paramlogs.forEach((elem, index) => {
+                                const xAxic = this.MixinClone(xAxi)
+                                const seriec = this.MixinClone(serie)
+                                legenddata.push(elem.param.param_name) // 加入图例
+                                op.yAxis.max = elem.param.max_limit_end + 5
+                                op.yAxis[0].name = '单位:' + key.unit
+                                zoom.xAxisIndex.push(index)
+                                xAxic.axisLine.lineStyle.color = this.colors[index] // 设置颜色
+                                xAxic.offset = 25 * index // 设置x轴偏移
+                                xAxic.axisPointer.label.formatter = function(params) {
+                                    return elem.param.param_name + params.value +
+                                        (params.seriesData.length ? ':' + params.seriesData[0].data : '')
+                                } // 设置提示信息格式化函数
+
+                                seriec.name = elem.param.param_name
+                                seriec.xAxisIndex = index
+                                seriec.markLine.data.push({ yAxis: elem.param.max_limit_stand })
+                                seriec.markLine.data.push({ yAxis: elem.param.min_limit_stand })
+
+                                const axidata = []
+                                const seriesdata = [] // X轴 值集合data数组
+                                if (elem && elem.logs) {
+                                    zoom.start = 100 - (10 * 100 / elem.logs.length)
+                                    elem.logs.forEach((log, idx) => {
+                                        axidata.push(this.unixToDate(log.log_time, 'MM-dd hh:mm'))
+
+                                        seriesdata.push(log.vs_value)
+                                    })
+                                }
+                                xAxic.data = axidata
+                                seriec.data = seriesdata
+                                op.xAxis.push(xAxic) // 推入X轴对象
+                                op.series.push(seriec) // 推入值对象
+                            })
+
+                            op.legend.data = legenddata // 设置图例
+                            op.dataZoom.push(zoom)
+                            key.option = op
+                        }
+                    })
+
+                    this.$nextTick(() => {
+                        this.vitalSignsLogs.forEach((key, index) => {
+                            echarts.init(document.getElementById('chart' + key.id)).setOption(key.option)
+                        })
+                        loading.close();
+                    })
+                })
+            }
+        }
+    })
+</script>
+</body>
+</html>

+ 257 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/AppUpdateActivity.kt

@@ -0,0 +1,257 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.content.Intent
+import android.os.Build
+import android.text.TextUtils
+import android.util.Log
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.UpdateLayBinding
+import com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper
+import com.wdkl.app.ncs.callingbed.helper.HttpHelper
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.api.UrlManager
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedAppUpdateContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedAppUpdatePresenter
+import com.xbh.sdk4.appcomm.AppCommHelper
+import kotlinx.android.synthetic.main.update_lay.*
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.io.File
+
+
+@Router(path = "/callingbed/update")
+class AppUpdateActivity :BaseActivity<BedAppUpdatePresenter, UpdateLayBinding>(), BedAppUpdateContract.View {
+    private val TAG = "AppUpdateActivity"
+
+    private val urlManager = UrlManager.build()
+
+    override fun getLayId(): Int {
+        return R.layout.update_lay
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        Constant.APP_UPDATING = true
+        if (!TextUtils.isEmpty(Constant.APP_PATH)) {
+            val downloadPath = urlManager.base + Constant.APP_PATH
+            Log.e(TAG, "start download: $downloadPath")
+            downLoadAPK(downloadPath)
+            if (!"rk3128".equals(Build.MODEL)) {
+                try {
+                    //启动云派app升级监听服务
+                    val intent = Intent()
+                    intent.setClassName("com.wd.app", "com.wd.app.MyService")
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                        //android8.0以上通过startForegroundService启动service
+                        startForegroundService(intent)
+                    } else {
+                        startService(intent)
+                    }
+                    Constant.yunpai_plugin = true
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                }
+            }
+        } else {
+            showMessage(R.string.download_error)
+            finish()
+        }
+    }
+
+    /**
+     * 下载APK包
+     */
+    fun downLoadAPK(url: String) {
+        Log.d(TAG, "downLoadAPK  url==$url")
+        activity_appupdate_dialog_progressview.setCurProgress(0)
+        activity_update_version.setText(Constant.APP_PATH.substringAfterLast("/"))
+        activity_update_version.setOnLongClickListener {
+            Log.d(TAG, "downLoadAPK cancel...")
+            HttpHelper.cancelRequestByTag(TAG)
+            activity.finish()
+
+            return@setOnLongClickListener true
+        }
+
+        HttpHelper.download(url, TAG, object : HttpHelper.DownloadListener {
+            override fun onDownloadSuccess() {
+                Log.d("download", "onDownloadSuccess==")
+                runOnUiThread {
+                    activity_update_text_download.setText(R.string.updating)
+                }
+
+                if ("rk3128".equals(Build.MODEL)) {
+                    //自产rk3128分机app升级
+                    startInstallApk()
+                } else if ("YUNPAI_H6".equals(Build.MODEL)) {
+                    //中兴8寸分机app升级
+                    startInstallAppYunPai()
+                } else if (BuildConfig.flag.equals(Constant.DEV_W_DCH)) {
+                    //大朝华7寸分机
+                    installApkFordch()
+                } else if (BuildConfig.flag.equals(Constant.DEV_W_YLD)) {
+                    //亿莱顿10寸分机,root下安装
+                    startInstallApk()
+                } else if (BuildConfig.flag.equals(Constant.DEV_W_LG_CBD)) {
+                    //朗国 静默安装
+                    installApkLangGuo()
+                } else if (BuildConfig.flag.equals(Constant.DEV_W_A133)) {
+                    //a133
+                    startInstallA133()
+                } else {
+                    AppUpdateHelper.installAPK(activity)
+                }
+            }
+
+            override fun onDownloading(progress: Int) {
+                runOnUiThread {
+                    activity_appupdate_dialog_progressview.setCurProgress(progress)
+                }
+            }
+
+            override fun onDownloadFailed() {
+                Log.d("download", "onDownloadFailed==")
+                finish()
+            }
+        })
+    }
+
+    fun startInstallApk() {
+        Thread{
+            AppUpdateHelper.updateApp(this, object : AppUpdateHelper.UpdateCallBack {
+                override fun onFailed() {
+                    runOnUiThread {
+                        showMessage(R.string.update_fail)
+                        finish()
+                    }
+                }
+
+                override fun onSuccess() {
+                    runOnUiThread {
+                        showMessage(R.string.update_success)
+                        //finish()
+                        //android.os.Process.killProcess(android.os.Process.myPid())
+                        //System.exit(0)
+                    }
+                }
+            })
+        }.start()
+    }
+
+    fun startInstallA133() {
+        Thread {
+            AppUpdateHelper.updateAppA133(this, object : AppUpdateHelper.UpdateCallBack {
+                override fun onFailed() {
+                    runOnUiThread {
+                        showMessage(R.string.update_fail)
+                    }
+                }
+
+                override fun onSuccess() {
+                    runOnUiThread {
+                        showMessage(R.string.update_success)
+                    }
+                }
+            })
+        }.start()
+    }
+
+    //云派8寸机app静默升级
+    fun startInstallAppYunPai() {
+        val apkAbsolutePath = AppUpdateHelper.FILE_APK_PATH + "/" + AppUpdateHelper.FILE_APK_NAME
+        val action = "com.miki.slient.INSTALL_CUSTOMER_PACKAGES"
+        val intent = Intent(action)
+        intent.putExtra("apkPath", apkAbsolutePath)
+        intent.putExtra("packageName", "com.miki.sensortest")
+        sendBroadcast(intent)
+    }
+
+    fun installApkForRk3288() {
+        val path = AppUpdateHelper.FILE_APK_PATH + "/" + AppUpdateHelper.FILE_APK_NAME
+        if (File(path).exists()) {
+            val intent = Intent("com.android.yf_slient_install")
+            intent.putExtra("path", path)  //要静默安装的apk路径
+            intent.putExtra("isboot", true)  //安装完成后是否启动
+            sendBroadcast(intent)
+        } else {
+            showMessage(R.string.update_fail)
+            finish()
+        }
+    }
+    fun installApkLangGuo() {
+        val path = AppUpdateHelper.FILE_APK_PATH + "/" + AppUpdateHelper.FILE_APK_NAME
+        if (File(path).exists()) {
+            val mAppCommHelper = AppCommHelper()
+            mAppCommHelper.silentInstallAppStart(path, true)
+        } else {
+            showMessage(R.string.update_fail)
+            finish()
+        }
+
+    }
+
+    fun installApkFordch() {
+        val path = AppUpdateHelper.FILE_APK_PATH + "/" + AppUpdateHelper.FILE_APK_NAME
+        if (File(path).exists()) {
+            val intent = Intent("install.apk.broadcast")
+            intent.putExtra("path", path)  //要静默安装的apk路径
+            intent.putExtra("pkgname", "com.wdkl.app.ncs.callingbed2")  //安装完成后是否启动
+            sendBroadcast(intent)
+        } else {
+            showMessage(R.string.update_fail)
+            finish()
+        }
+    }
+
+
+    override fun bindEvent() {
+        //
+    }
+
+    override fun onBackPressed() {
+        //
+    }
+
+    override fun destory() {
+        Constant.APP_UPDATING = false
+    }
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+        //
+    }
+
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+        //
+    }
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+    }
+    //开始获取数据
+    override fun start() {
+        //
+    }
+
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+}

+ 458 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivationActivity.kt

@@ -0,0 +1,458 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.app.zhyl.ZhylManager
+import android.content.Intent
+import android.net.Uri
+import android.net.wifi.WifiManager
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.config.NetEngineConfig
+import com.enation.javashop.net.engine.model.NetState
+import com.enation.javashop.net.engine.plugin.exception.RestfulExceptionInterceptor
+import com.enation.javashop.utils.base.config.BaseConfig
+import com.google.gson.Gson
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.CallingbedActivationBinding
+import com.wdkl.app.ncs.callingbed.dialog.ServicesDialogHelper
+import com.wdkl.app.ncs.callingbed.dialog.SystemDialogHelper
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory
+import com.wdkl.app.ncs.callingbed.helper.*
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.service.ViewService
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig
+import com.wdkl.app.ncs.callingbed.utils.SPUtils
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.utils.EcodeHelper
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.api.UrlManager
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.CallingbedActivationContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.CallingbedActivationPresenter
+import com.wdkl.ncs.android.middleware.model.ThirdServerInfo
+import com.wdkl.ncs.android.middleware.model.vo.BedDeviceInfoVO
+import com.wdkl.ncs.android.middleware.tcp.enums.DeviceTypeEnum
+import com.wdkl.ncs.android.middleware.udp.ServerInfoUtil
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import kotlinx.android.synthetic.main.callingbed_activation.*
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.util.*
+import java.util.concurrent.TimeUnit
+
+/**
+  * 激活页面
+* */
+@Router(path = "/callingbed/activation")
+class CallingbedActivationActivity  : BaseActivity<CallingbedActivationPresenter, CallingbedActivationBinding>(), CallingbedActivationContract.View {
+    private val TAG = "CallingbedActivationActivity"
+    val QR_CODE_PATH = "http://m.wdklian.com/care/apk/care.user?type=NCS_DEVICE"
+    private val uninstallApk = false
+    private val APP_NAME = "com.wdkl.callingbed2"
+    private val handler by lazy { Handler(Looper.getMainLooper()) }
+    //服务器是否请求成功
+    private var serverSuccess = false
+    //是否重启
+    private var cancelRestart = false
+
+    private var clickTime: Long = 0
+    private var clickTimes: Int = 1
+
+
+
+     var viewService: ViewService? = null
+
+    override fun getLayId(): Int {
+
+        val currentLanguage: String = Locale.getDefault().getLanguage()
+        if (currentLanguage.equals("es")){
+            return R.layout.callingbed_activation_es
+        }else{
+            return R.layout.callingbed_activation
+        }
+
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        BaseConfig.getInstance().addActivity("WelcomeActivity", "AppUpdateActivity", "CallingbedActivity",
+                "CallingbedActivationActivity", "SystemActivity",
+                "WebviewActivity","DeviceLinkageActivity","DeviceSystemActivity","SleepMonitoringActivity")
+        NetEngineConfig.init(baseContext)
+                .openLogger()
+                .addNetInterceptor(RestfulExceptionInterceptor())
+
+        //init
+        NetHelper.getInstance().init(baseContext)
+        //初始化串口
+        HardWareFactory.getHardTools().init(this)
+        //注册方式
+        HardWareFactory.getHardTools().Registration(this)
+
+        //xCrash catcher
+        XCrashUtils().init(application)
+
+
+        checkServer()
+    }
+
+    override fun bindEvent() {
+        //设备重启
+        activation_settings_button.setOnClickListener {
+            //RebootDialogHelper.showDialog(activity)
+            Utils.hideStatusBar(activity, false)
+            AppUpdateHelper.restartApp(activity)
+        }
+        //系统设置
+        activation_system_button.setOnClickListener {
+            SystemDialogHelper.showDialog(activity, 1)
+        }
+        //服务器设置
+        activation_services_button.setOnClickListener {
+            ServicesDialogHelper.showDialog(activity, object : ServicesDialogHelper.ClickListener {
+                override fun onClick(bedVO: String?) {
+                    setfuq()
+                }
+            })
+        }
+
+        activation_qr_code.setOnClickListener {
+            val time = System.currentTimeMillis()
+            if (time - clickTime < 1500) {
+                clickTimes++
+            } else {
+                clickTimes = 1
+            }
+
+            if (clickTimes >15) {
+                showMessage("enable status bar")
+                Utils.hideStatusBar(activity, false)
+                clickTimes = 1
+            }
+            clickTime = time
+        }
+        //网络设置
+        activation_language_button.setOnClickListener {
+            if (BuildConfig.flag == Constant.DEV_W_A133) {
+                //关闭守护进程
+               ZhylManager.getInstance(BaseApplication.appContext).sys_setDaemonsActivity("", 5000, false)
+            }
+
+            val intentWifi = Intent(WifiManager.ACTION_PICK_WIFI_NETWORK) // WIFI网络
+            intentWifi.putExtra("only_access_points", true);
+            intentWifi.putExtra("extra_prefs_show_button_bar", true) // 展示返回按钮
+            intentWifi.putExtra("extra_prefs_set_back_text", getString(R.string.back_button_message)) // 设置文字
+            intentWifi.putExtra("extra_prefs_set_next_text", "") // 隐藏下一步的按钮
+            startActivityForResult(intentWifi, 1);
+            Thread.sleep(1000)
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {
+                val serviceIntent = Intent(this, ViewService::class.java)
+                startService(serviceIntent)
+                //隐藏虚拟导航栏
+               HardWareFactory.getHardTools().startbar(true)
+
+            }
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        showUI()
+        HardWareFactory.getHardTools().startbar(false)
+        if (BuildConfig.flag == Constant.DEV_W_A133) {
+           ZhylManager.getInstance(BaseApplication.appContext).sys_setDaemonsActivity("com.wdkl.app.ncs.callingbed2/com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity", 10000, true)
+        }
+        val serviceIntent = Intent(this, ViewService::class.java)
+        stopService(serviceIntent)
+
+    }
+
+    override fun destory() {
+        serverSuccess = true
+        val serviceIntent = Intent(this, ViewService::class.java)
+        stopService(serviceIntent)
+    }
+
+    private fun showUI(){
+        if (BuildConfig.is_mom.toBoolean()){
+            SettingConfig.setScene(activity, 1)
+            activation_img.setBackgroundResource(R.mipmap.activation_p_mom_bg)
+            activation_settings_button.setBackgroundResource(R.drawable.shape_main_bt_mom_bg)
+            activation_system_button.setBackgroundResource(R.drawable.shape_main_bt_mom_bg)
+            activation_services_button.setBackgroundResource(R.drawable.shape_main_bt_mom_bg)
+        }else{
+            SettingConfig.setScene(activity, BuildConfig.device_type.toInt())
+        }
+        val isActivation = SPUtils.get(this, Constant.APP_ACTIVATION, "");
+        if (isActivation.equals("Activated")){
+            activation_title.setText(R.string.connect_server_failed)
+            activation_title.setTextColor(resources.getColor(R.color.red_color))
+            activation_title_msg.setText(R.string.connect_check)
+            activation_title.setTextColor(resources.getColor(R.color.red_color))
+        }else{
+            activation_title.setText(R.string.str_check_activation)
+            activation_title.setTextColor(resources.getColor(R.color.white))
+            activation_title_msg.setText(R.string.str_set_active_param)
+            activation_title.setTextColor(resources.getColor(R.color.white))
+        }
+
+        activation_zcm.text=  Constant.DEVICE_REGISTER_ID
+        val buildUrl = UrlManager.build()
+        activation_fuq.text=   buildUrl.buyer.substringAfterLast("//").substringBefore(":")
+        //设置二维码
+        setQrcode()
+        val netInfo = NetHelper.getNetInfo(activity)
+        activation_v.text =  BuildConfig.VERSION_NAME + "_" + BuildConfig.VERSION_CODE + "_" + Build.MODEL
+        activation_ip.text = NetHelper.getInstance().localIP
+        if (netInfo != null) {
+            activation_wg.text = netInfo.gateway
+            activation_ym.text = netInfo.netMask
+        }
+    }
+
+     fun setfuq(){
+         activation_fuq.text=CommonUtils.getUrl(this)
+         showMessage(R.string.str_reboot_active)
+    }
+
+    //设置二维码
+    private fun setQrcode(){
+        Thread{
+            //val logoBitmap = BitmapFactory.decodeResource(resources, R.mipmap.erlogo)
+            var builder = StringBuilder()
+            builder.append(QR_CODE_PATH)
+            builder.append("&code=")
+            builder.append(Constant.DEVICE_CODE)
+            builder.append("&mac=")
+            builder.append(Constant.DEVICE_REGISTER_ID)
+            builder.append("&model=")
+            builder.append(Constant.DEVICE_MODEL)
+            builder.append("&hard_ver=")
+            builder.append(Constant.DEVICE_HARD_VER)
+            builder.append("&soft_ver=")
+            builder.append(Constant.DEVICE_SOFT_VER)
+            builder.append("&device_type=")
+            builder.append(DeviceTypeEnum.DIGIT_BED_DEVICE.value())
+            builder.append("&device_name=")
+            builder.append(DeviceTypeEnum.DIGIT_BED_DEVICE.typeName())
+            val code = EcodeHelper().createQRImage(builder.toString(), 250, null)
+            activity.runOnUiThread {
+                activation_qr_code?.setImageBitmap(code)
+            }
+        }.start()
+    }
+
+
+
+    private fun checkServer() {
+        Thread {
+            while (!serverSuccess) {
+                val okHttpClient = OkHttpClient().newBuilder()
+                        .connectTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .readTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .writeTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .build()
+                val url: String = CommonUtils.getUrl(BaseApplication.appContext)
+                val port: String = CommonUtils.getUrlPort(BaseApplication.appContext)
+                val request = Request.Builder()
+                        .url("http://$url:$port/ncs_url/server_info")
+                        .get()
+                        .build()
+
+                try {
+                    Log.i(TAG, "start check server: $url,$port")
+                    val response = okHttpClient.newCall(request).execute()
+                    Log.i(TAG, "check end: " + Constant.DEVICE_REGISTER_ID)
+                    if (response != null && response.isSuccessful) {
+                        //接口数据获取成功,检查设备是否已注册
+                        if (!TextUtils.isEmpty(Constant.DEVICE_REGISTER_ID)) {
+                            presenter.getDeviceInfo(Constant.DEVICE_REGISTER_ID)
+                        }
+                    } else {
+                        //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                        val info = ServerInfoUtil.get(Constant.DEVICE_REGISTER_ID!!)
+                        checkServerInfo(info)
+                    }
+                } catch (e: Exception) {
+                    //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                    Log.e(TAG, "check server exception:")
+                    e.printStackTrace()
+                    val info = ServerInfoUtil.get(Constant.DEVICE_REGISTER_ID!!)
+                    checkServerInfo(info)
+                }
+
+                try {
+                    Thread.sleep(45000)
+                } catch (ex: Exception) {
+                    ex.printStackTrace()
+                }
+            }
+        }.start()
+    }
+
+
+    private fun checkServerInfo(info: ThirdServerInfo?) {
+        //检查获取到的服务器ip是否可用,可用则重启app重新初始化,不可用则什么都不做,等待下次重新获取服务器ip
+        if (info != null) {
+            if (info.thirdServer == null || info.thirdServerPort == null) {
+                Log.d(TAG, "server info data null")
+                showMsgMain("get server data null")
+            } else {
+                val okHttpClient = OkHttpClient().newBuilder()
+                        .connectTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .readTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .writeTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .build()
+                val request = Request.Builder()
+                        .url("http://${info.thirdServer}:${info.thirdServerPort}/ncs_url/server_info")
+                        .get()
+                        .build()
+
+                try {
+                    val response = okHttpClient.newCall(request).execute()
+                    if (response != null && response.isSuccessful) {
+                        //接口数据获取成功,稍后重启app
+                        serverSuccess = true
+                        CommonUtils.setUrl(activity, info.thirdServer)
+                        CommonUtils.setUrlPort(activity, info.thirdServerPort.toString())
+                        showMsgMain("restart...")
+                        handler.postDelayed({
+                            if (!cancelRestart) {
+                                AppUpdateHelper.restartApp(activity)
+                            }
+                        }, 10000)
+                    }
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    showMsgMain("server error or net error")
+                }
+            }
+        } else {
+            Log.d(TAG, "server info null")
+            showMsgMain("get server null")
+            checkNet()
+        }
+    }
+
+    override fun showDeviceInfo(deviceInfo: BedDeviceInfoVO) {
+        //获取到设备信息,跳转到主界面
+        serverSuccess = true
+        Constant.SIP_ID = deviceInfo.sipId
+        Constant.DEVICE_ID = deviceInfo.id
+        Constant.PART_ID = deviceInfo.partId
+        Constant.BED_NAME = deviceInfo.fullName
+
+        Constant.DEVICE_CODE = deviceInfo.code
+        Constant.DEVICE_MODEL = deviceInfo.model
+        Constant.DEVICE_SOFT_VER = deviceInfo.softVer
+        Constant.DEVICE_HARD_VER = deviceInfo.hardVer
+        Constant.DEVICE_INFO = Gson().toJson(deviceInfo)
+
+        if (deviceInfo.partName != null) {
+            Constant.PART_NAME = deviceInfo.partName
+        }
+        if (deviceInfo.part_union_id != null) {
+            Constant.PART_UNION_ID = deviceInfo.part_union_id
+        }
+        if (deviceInfo.customerId != null) {
+            Constant.CUSTOM_ID = deviceInfo.customerId
+        }
+
+        if (deviceInfo.memberId != null) {
+            Constant.MEMBER_ID = deviceInfo.memberId
+        }
+
+        if (deviceInfo.status != null) {
+            Constant.DEVICE_STATUS = deviceInfo.status
+        }
+            val intent = Intent()
+            intent.setClass(activity, CallingbedActivity::class.java)
+            activity.startActivity(intent)
+
+        finish()
+    }
+
+    private fun showMsgMain(msg: String) {
+        runOnUiThread {
+            showMessage(msg)
+        }
+    }
+    //网络异常计数
+    private var netErrCount : Int = 0
+    private fun checkNet() {
+        /*
+        * 检查网络情况,若tcp断开连接多次且IP也是空的则网络异常,重启设备
+        * 仅对3128设备有效
+         */
+        if (Build.MODEL.equals("rk3128") || BuildConfig.flag == Constant.DEV_W_A133) {
+            Log.e("checkNet", "checkNet --> netErrCount: " + netErrCount + ", IP isEmpty: " + TextUtils.isEmpty(NetHelper.getInstance().localIP))
+            var count = SettingConfig.getNetErrResetCount(this)
+            if (!Constant.TCP_CONNECTED && TextUtils.isEmpty(NetHelper.getInstance().localIP)) {
+                netErrCount++
+            } else {
+                netErrCount = 0
+                if (count > 0) {
+                    count = 0
+                    SettingConfig.setNetErrResetCount(this, count)
+                }
+            }
+
+            if (netErrCount >= 5) {
+                //如果重启次数超过8次还是无网则不再重启
+                if (count < 8) {
+                    count++
+                    SettingConfig.setNetErrResetCount(this, count)
+                    handler.postDelayed({
+                        Log.e("reboot", "重启")
+                        HardWareFactory.getHardTools().Registration(this)
+                    }, 5000)
+                } else {
+                    runOnUiThread {
+                        WarningDialogHelper.showDialog(this)
+                    }
+                }
+            }
+        }
+    }
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+        Log.e(TAG, message)
+        showMessage(message)
+    }
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    //开始获取数据
+    override fun start() {
+    }
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+    }
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+
+}

+ 937 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivity.kt

@@ -0,0 +1,937 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+
+import android.content.*
+import android.content.pm.PackageManager
+import android.graphics.Color
+import android.net.ConnectivityManager
+import android.os.*
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import android.view.KeyEvent
+import android.view.View
+import android.view.ViewTreeObserver
+import androidx.fragment.app.Fragment
+import com.alibaba.fastjson.JSON
+import com.alibaba.fastjson.JSONObject
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.model.NetState
+import com.google.gson.Gson
+
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.agreement.CallingbedAgreement
+import com.wdkl.app.ncs.callingbed.bt_gateway.*
+import com.wdkl.app.ncs.callingbed.databinding.CallingbedMainNewBinding
+
+import com.wdkl.app.ncs.callingbed.fragment.*
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory
+import com.wdkl.app.ncs.callingbed.helper.*
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig
+import com.wdkl.app.ncs.callingbed.sleep.SleepService
+
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.core.locale.LocaleMangerUtils
+import com.wdkl.ncs.android.lib.core.locale.SettingConfigNew
+import com.wdkl.ncs.android.lib.utils.*
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.entity.CallingItem
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedCallingbedActivityContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedCallingbedActivityPresenter
+import com.wdkl.ncs.android.middleware.model.ServerInfo
+import com.wdkl.ncs.android.middleware.model.dos.AppVersionDO
+import com.wdkl.ncs.android.middleware.model.dos.DeviceDO
+import com.wdkl.ncs.android.middleware.model.dos.PartSettingDO
+import com.wdkl.ncs.android.middleware.model.dos.RoleDO
+import com.wdkl.ncs.android.middleware.model.dto.TcpSeverDTO
+import com.wdkl.ncs.android.middleware.model.vo.*
+import com.wdkl.ncs.android.middleware.tcp.TcpClient
+import com.wdkl.ncs.android.middleware.tcp.channel.*
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
+import com.wdkl.ncs.android.middleware.tcp.enums.DeviceTypeEnum
+import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction
+import com.wdkl.ncs.android.middleware.tcp.enums.TcpType
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import com.wdkl.ncs.android.middleware.utils.StringUtil
+import com.wdkl.ncs.janus.util.JanusConstant
+import kotlinx.android.synthetic.main.acivity_time_setting.*
+import kotlinx.android.synthetic.main.callingbed_main_new.*
+import kotlinx.android.synthetic.main.callingbed_setting_main.*
+import kotlinx.android.synthetic.main.callingbed_test_main.*
+import kotlinx.android.synthetic.main.view_title_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.io.File
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.util.*
+import kotlin.collections.ArrayList
+
+
+/**
+ * Callingbed2Activity :BaseActivity<Callingbed2ActivityPresenter, Callingbed2MainLayBinding>
+ *     Callingbed2ActivityPresenter: 位置com.wdkl.ncs.android.middleware.logic.presenter.callingbed2
+ *     Callingbed2MainLayBinding: 位置callingbed2_main_lay.xml
+ *     Callingbed2ActivityContract: 位置com.wdkl.ncs.android.middleware.logic.contract.callingbed2
+ */
+
+@Router(path = "/callingbed/main")
+class CallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, CallingbedMainNewBinding>(), BedCallingbedActivityContract.View, CallingbedAgreement {
+
+    var TAG = CallingbedActivity::class.java.getSimpleName()
+
+    private lateinit var receiver: TimeReceiver
+
+    private var curFragment = ""
+    //首页
+    private val mainFragment = "main_fragment"
+    //公寓首页
+    private val apartmentFragment = "apartment_fragment"
+
+    private var initialized :Boolean = false
+    private var tcpConnect: Boolean = false
+    private var loaded: Boolean = false
+
+    //网络异常计数
+    private var netErrCount : Int = 0
+
+    private val handler by lazy { Handler(Looper.getMainLooper()) }
+
+    private var SleepIntent: Intent? = null
+    private var service_sl: SLService? = null
+    private var SleepServiceBinder: SleepService.ServiceBinder? = null
+    private var bindSleepService = false
+
+    private var copyDone = false
+
+    private var language = "zh"
+
+    companion object {
+        //lateinit var instance: CallingbedActivity
+        var sosItemList = ArrayList<CallingItem>()
+        var callingList = ArrayList<CallingItem>()
+
+        fun checkIncomingCall(bedDeviceId: Int?): Boolean {
+            if (callingList.size > 0) {
+                for (item in callingList) {
+                    if (item.interactionVO.fromDeviceId == bedDeviceId) {
+                        return true
+                    }
+                }
+            }
+            return false
+        }
+    }
+
+
+    override fun getLayId(): Int {
+        return R.layout.callingbed_main_new
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        //直接
+        if (!apartmentFragment.equals(curFragment)) {
+            switchFragment(R.id.callingbed_main_frame, apartmentFragment(), apartmentFragment)
+        }
+
+        language = LocaleMangerUtils.getApplicationLocale().language
+
+        //注册广播
+        regReceiver()
+
+        RecordHelper.getInstance().init()
+
+        EventBus.getDefault().register(this)
+
+        SoundPoolManager.getInstance().init()
+
+        //更新状态图标
+        updateNetState()
+
+        //禁止下拉状态栏
+        Utils.setStatusBarDisable(activity, Utils.STATUS_BAR_DISABLE_EXPAND)
+
+        //保持屏幕常亮
+//        AppTool.Setting.setScreenOffTimeOut(applicationContext, 35000)
+
+        presenter.loadServerInfo()
+
+        SpeechUtil.getInstance().init(applicationContext)
+        val dm = resources.displayMetrics
+        Constant.DEVICE_WIDTH = dm.widthPixels
+        Constant.DEVICE_HEIGHT = dm.heightPixels
+        Constant.DEVICE_ORIENTATION = resources.configuration.orientation
+
+    }
+
+
+    private fun switchFragment(id: Int, fragment: Fragment, tag: String) {
+        supportFragmentManager.beginTransaction()
+                .replace(id, fragment, tag)
+                .commitAllowingStateLoss()
+        curFragment = tag
+    }
+
+    private fun initDevice() {
+        if (!TextUtils.isEmpty(Constant.DEVICE_REGISTER_ID)) {
+            presenter.loadDeviceInfo(Constant.DEVICE_REGISTER_ID)
+        }
+    }
+
+
+
+    override fun bindEvent() {
+
+    }
+
+    override fun checkAppVersion() {
+        Constant.APP_PATH = ""
+        //获取APP版本信息,7寸分机type=204,8寸可视分机用104
+        if (Constant.PART_ID != null) {
+            //判断是不是探视分机 ,伊莱顿类型分机主要用在探视分机,在后台更新项也必须添加到可视类型
+         if (BuildConfig.flag == Constant.DEV_W_YLD) {
+             presenter.getAppVersion(Constant.PART_ID, 104)
+            } else {
+             presenter.getAppVersion(Constant.PART_ID, 204)
+            }
+        }
+        Log.d("AppUpdate", "checkAppVersion =====>>  Constant.PART_ID: " + Constant.PART_ID)
+    }
+
+
+    override fun onStart() {
+        super.onStart()
+        //设备已注册,隐藏导航栏
+        if (Constant.DEVICE_ID != -1 && Settings.System.canWrite(this)) {
+            Utils.hideStatusBar(activity, true)
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+    }
+
+    override fun destory() {
+        unRegReceiver()
+        EventBus.getDefault().unregister(this)
+        Constant.CALL_STATE = Constant.CALL_STANDBY
+
+        HardWareFactory.getHardTools().unInit()
+        handler.removeCallbacksAndMessages(null)
+        SoundPoolManager.getInstance().release()
+
+        stopSLService()
+
+    }
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+        showMessage(message)
+    }
+
+    //没有网络
+    override fun onNoNet() {
+        showMessage("none network")
+    }
+
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+    }
+
+    //开始获取数据
+    override fun start() {
+    }
+
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+
+    //显示设备信息
+    override fun showDeviceInfo(deviceInfo: BedDeviceInfoVO) {
+        Constant.SIP_ID = deviceInfo.sipId
+        Constant.DEVICE_ID = deviceInfo.id
+        Constant.PART_ID = deviceInfo.partId
+        Constant.BED_NAME = deviceInfo.fullName
+
+        Constant.DEVICE_CODE = deviceInfo.code
+        Constant.DEVICE_MODEL = deviceInfo.model
+        Constant.DEVICE_SOFT_VER = deviceInfo.softVer
+        Constant.DEVICE_HARD_VER = deviceInfo.hardVer
+        Constant.DEVICE_INFO = Gson().toJson(deviceInfo)
+
+
+
+        if (deviceInfo.status != null) {
+            Constant.DEVICE_STATUS = deviceInfo.status
+        }
+        view_title_layout_tv_hospital_name.text = deviceInfo.partDisplay
+
+        if (deviceInfo.partName != null) {
+            Constant.PART_NAME = deviceInfo.partName
+        }
+        if (deviceInfo.part_union_id != null) {
+            Constant.PART_UNION_ID = deviceInfo.part_union_id
+        }
+
+        view_title_layout_tv_hospital_name.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+            override fun onGlobalLayout() {
+                if (view_title_layout_tv_hospital_name.width < view_title_layout_tv_hospital_name.paint.measureText(view_title_layout_tv_hospital_name.text.toString())) {
+                    view_title_layout_tv_hospital_name.isSelected = true  // 开启跑马灯效果
+                    view_title_layout_tv_hospital_name.isFocusable = true
+                    view_title_layout_tv_hospital_name.isFocusableInTouchMode = true
+                    view_title_layout_tv_hospital_name.requestFocus()
+                } else {
+                    view_title_layout_tv_hospital_name.isSelected = false  // 关闭跑马灯效果
+                    view_title_layout_tv_hospital_name.isFocusable = false
+                    view_title_layout_tv_hospital_name.isFocusableInTouchMode = false
+                }
+                view_title_layout_tv_hospital_name.viewTreeObserver.removeOnGlobalLayoutListener(this)
+            }
+        })
+        view_title_layout_tv_no.text = "ID: " + deviceInfo.id
+        initialized = true
+
+        if (deviceInfo.customerId != null) {
+            Constant.CUSTOM_ID = deviceInfo.customerId
+        }
+
+        if (deviceInfo.memberId != null) {
+            Constant.MEMBER_ID = deviceInfo.memberId
+        }
+
+        Utils.hideStatusBar(activity, true)
+
+        if (TextUtils.isEmpty(Constant.SIP_ID)) {
+            showMessage("SIP ID empty")
+        }
+        if (Constant.DEVICE_STATUS == 0) {
+            showMessage(R.string.device_disable)
+        }
+
+        //加载分机所绑定紧急按钮设备信息
+        if (deviceInfo.frameId != null) {
+            Constant.FRAME_ID = deviceInfo.frameId
+            presenter.getEmergencyDeviceInfo(deviceInfo.frameId)
+            presenter.loadDevicesList(Constant.FRAME_ID)
+        }
+        presenter.loadPartSettings(Constant.PART_ID)
+
+    }
+
+    override fun showCustomInfo(customInfo: CustomerInfoVO) {
+
+    }
+
+    //显示交互记录
+    override fun showCallRecords(record: CallRecordVO) {
+        //
+    }
+
+    override fun setPartSettings(partSetting: PartSettingDO) {
+        try {
+            //设置白昼起止时间
+            SettingConfig.setInitialDayTime(this, partSetting.dayStart.substring(0, 5))
+            SettingConfig.setEndOfDay(this, partSetting.nightStart.substring(0, 5))
+
+            //分机白天夜晚亮度
+            SettingConfig.setExtensionDaytimeBrightness(this, partSetting.dayLight)
+            SettingConfig.setExtensionNightBrightness(this, partSetting.nightLight)
+
+            //分机白天夜晚护理灯 也就是LED灯的亮度
+            SettingConfig.setExtensionDaytimeLEDBrightness(this, partSetting.dayNurseLed)
+            SettingConfig.setExtensionNightLEDBrightness(this, partSetting.nightNurseLed)
+
+            //分机白天夜晚系统音量
+            SettingConfig.setExtensionDaytimeSystemVolume(this, partSetting.dayBedVol)
+            SettingConfig.setExtensionNightSystemVolume(this, partSetting.nightBedVol)
+
+            //分机通话音量  没做白昼区分
+            SettingConfig.setExtensionCallVolume(this, partSetting.dayBedVol)
+
+            SettingConfig.setSipOverTime(this, partSetting.sipOvertime)
+            SettingConfig.setSleepTime(this, partSetting.sleepSecondsBed)
+
+            Constant.doctorTitle = partSetting.doctorTitle
+            Constant.nurseTitle = partSetting.nurseTitle
+            if (partSetting.doctorValid != null) {
+                Constant.doctorValid = partSetting.doctorValid
+            }
+            if (partSetting.nurseValid != null) {
+                Constant.nurseValid = partSetting.nurseValid
+            }
+
+            VoiceManagerUtil.setCallVoice(activity, partSetting.dayBedVol)
+
+            if (partSetting.autoAccept != null && partSetting.autoAccept == 1) {
+                SettingConfig.setAutoAnswer(activity, true)
+            } else {
+                SettingConfig.setAutoAnswer(activity, false)
+            }
+
+            if (partSetting.convenientServiceEnabled != null) {
+                Constant.convenientServiceEnabled = partSetting.convenientServiceEnabled
+            }
+
+            if (partSetting.recordEnabled != null && partSetting.recordEnabled == 1) {
+                SettingConfig.setRecordEnable(activity, true)
+            } else {
+                SettingConfig.setRecordEnable(activity, false)
+            }
+            HardWareFactory.getHardTools().setTime(this, 0, partSetting.time_zone)
+
+            //通过服务端设置语言
+            if (SettingConfigNew.getLanguageMode(activity) == 0) {
+                var needReboot = false
+                if ("cn".equals(partSetting.language)) {
+                    //中文
+                    if (SettingConfigNew.getLanguageId(activity) != 2) {
+                        needReboot = true
+                    }
+                    SettingConfigNew.setLanguageId(activity, 2)
+                } else if ("en".equals(partSetting.language)) {
+                    //英文
+                    if (SettingConfigNew.getLanguageId(activity) != 1) {
+                        needReboot = true
+                    }
+                    SettingConfigNew.setLanguageId(activity, 1)
+                } else if ("es".equals(partSetting.language)) {
+                    //西班牙语
+                    if (SettingConfigNew.getLanguageId(activity) != 3) {
+                        needReboot = true
+                    }
+                    SettingConfigNew.setLanguageId(activity, 3)
+                } else if ("ru".equals(partSetting.language)) {
+                    //俄语
+                    if (SettingConfigNew.getLanguageId(activity) != 4) {
+                        needReboot = true
+                    }
+                    SettingConfigNew.setLanguageId(activity, 4)
+                }
+                if (needReboot) {
+                    handler.postDelayed({
+                        AppUpdateHelper.restartApp(activity)
+                    }, 10000)
+                }
+            }
+
+        } catch (ex: Exception) {
+            showMessage(StringUtil.getResString(R.string.setting_params_error) + ex.message)
+            ex.printStackTrace()
+        }
+
+        updateSettings(true)
+
+        EventBus.getDefault().post(MessageEvent("updateCustom", Constant.EVENT_UPDATE_CUSTOM))
+
+
+    }
+
+    override fun setTcpServerHost(tcpSeverDTO: TcpSeverDTO) {
+    }
+
+    override fun setServerInfo(data: ServerInfo) {
+        if (loaded) {
+            return
+        }
+        loaded = true
+        Constant.TCP_SERVER_URL = data.tcpLocalIp
+        Constant.TCP_PORT = data.tcpPort
+        Constant.TCP_HEART_BEAT = data.tcpIdleSeconds
+        JanusConstant.JANUS_URL = "ws://" + data.rtcLocalIp + ":" + data.rtcPort
+        JanusConstant.STUN_SERVER = arrayOf<String>(data.stunServer)
+        //JanusConstant.TURN_SERVER = data.turnServer
+
+        JanusConstant.Record_Dir = data.recordDir
+
+        if (data.tcpVsPort != null) {
+            Constant.TCP_VS_PORT = data.tcpVsPort
+        }
+
+        if (data.httpSystemPort != null) {
+            Constant.HTTP_SERVER_URL = "http://" + data.httpLocalIp + ":" + data.httpSystemPort
+        }
+
+        //开启TCP连接
+        startTcp()
+        showMessage("tcp connect...host: " + Constant.TCP_SERVER_URL + ", port: " + Constant.TCP_PORT)
+
+        SettingConfig.setNetErrResetCount(this, 0)
+        WarningDialogHelper.dismiss()
+
+        if (data.sipIp != null) {
+            Constant.sip_ip = data.sipIp
+        }
+        if (data.sipPort != null) {
+            Constant.sip_port = data.sipPort
+        }
+
+        Thread(Runnable {
+            while (!initialized) {
+                runOnUiThread(Runnable {
+                    initDevice()
+                })
+                try {
+                    Thread.sleep(20000)
+                } catch (e: Exception) {
+                    //
+                }
+            }
+        }).start()
+
+        if (SettingConfig.getSLEEPGatewayOn(activity)) {
+            //启动床垫服务
+            startSLService()
+        }
+
+        //30s后检查版本
+        handler.postDelayed({
+            //检查版本
+            checkAppVersion()
+        }, 30000)
+    }
+
+    override fun loadAppVersion(appInfo: AppVersionDO) {
+        val newAppVersion = appInfo.versionCode.substring(1)
+        Log.d("AppUpdate", "loadAppVersion =====>>  newAppVersion: " + newAppVersion + ", curAppVersion: " + BuildConfig.VERSION_NAME + ", path: " + appInfo.appPath)
+        showMessage("current version: " + BuildConfig.VERSION_NAME + "_" + BuildConfig.VERSION_CODE + ", new version: " + newAppVersion + "_" + appInfo.versionNo)
+        var version = BuildConfig.VERSION_CODE.toInt()
+        if (version < appInfo.versionNo) {
+            if (!Constant.APP_UPDATING) {
+                //showMessage("即将升级...")
+                Constant.APP_PATH = appInfo.appPath
+                Constant.APP_UPDATING = true
+
+                UpdateTipsDialogHelper.showDialog(activity)
+            } else {
+                showMessage(R.string.updating)
+            }
+        } else {
+            showMessage(R.string.update_no_required)
+        }
+    }
+
+    override fun showEmergencyInfo(deviceInfo: DeviceDO) {
+        if (deviceInfo.id != null) {
+            Constant.EMERGENCY_ID = deviceInfo.id
+        }
+    }
+
+    override fun loadRoles(roles: List<RoleDO>) {
+
+    }
+
+    override fun loadCommunicateDevice(communicateDevice: List<BedCommunicateDeviceVO>) {
+
+    }
+
+    override fun loadPhoneWhiteList(whiteList: List<String>) {
+
+    }
+
+    private var allOrders = ArrayList<DeviceLinVo>()
+
+    /**
+     * 联动设备信息
+     * */
+    override fun setDevicesList(advices: ArrayList<DeviceLinVo>) {
+        if (advices.size>0) {
+            allOrders = advices
+            for (i in 0 until allOrders.size) {
+                val device = allOrders[i]
+                //是睡眠床垫的话
+                if (device.device_type == DeviceTypeEnum.SLEEPMATTRESS.value()) {
+                    Constant.sleep_sn = device.eth_mac
+                    return
+                }
+            }
+        }
+
+    }
+
+    private fun startTcp() {
+        if (Constant.TCP_SERVER_URL != null && !tcpConnect) {
+            tcpConnect = true
+            Thread(Runnable { TcpClient.getInstance().init(Constant.TCP_SERVER_URL, Constant.TCP_PORT, Constant.TCP_HEART_BEAT) }).start()
+        }
+    }
+
+    private fun regReceiver() {
+        receiver = TimeReceiver()
+        var intentFilter = IntentFilter()
+        intentFilter.addAction(Intent.ACTION_TIME_TICK)
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
+        intentFilter.addAction(Constant.KEY_CALL_UP)
+        intentFilter.addAction(Constant.KEY_HOME_UP)
+        //卡尔10寸横屏
+        intentFilter.addAction(Constant.HOOK_OFF)
+        intentFilter.addAction(Constant.HOOK_ON)
+
+        registerReceiver(receiver, intentFilter)
+    }
+
+    private fun unRegReceiver() {
+        unregisterReceiver(receiver)
+    }
+
+
+
+
+
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        //代码同步
+        synchronized(Unit) {
+            handleTcpModel(messageEvent)
+        }
+    }
+
+    private fun handleTcpModel(messageEvent: MessageEvent) {
+        when (messageEvent.getType()) {
+            //TCP消息处理
+            Constant.EVENT_TCP_MSG -> {
+                if (messageEvent.message is TcpModel) {
+                    val tcpModel = messageEvent.message as TcpModel
+                    Log.d("TCP", "received tcp action: " + tcpModel.action + ", type: " + tcpModel.type)
+                if (tcpModel.type == TcpType.DEVICE) {
+                        //检查APP版本
+                        if (tcpModel.getAction() == TcpAction.DeviceAction.APP_UPDATE) {
+                            Util.wakeUpAndUnlock()
+                            checkAppVersion()
+                        } else if (tcpModel.action == TcpAction.DeviceAction.RESTART) {
+                            //后台做了重发此消息的机制.防止网络不好的时候没收到app重启,设备信息不刷新
+                            if (!TextUtils.isEmpty(tcpModel.tid)) {
+                                TcpClient.getInstance().sendMsg(tcpModel.toJson())
+                            }
+                            Util.wakeUpAndUnlock()
+                            //收到重启app指令,若当前处于正常待机状态则直接重启app,否则等待通话结束再重启
+                            if (Constant.CALL_STATE == Constant.CALL_STANDBY) {
+                                AppUpdateHelper.restartApp(activity)
+                            } else {
+                                Constant.LATER_RESTART = true
+                            }
+                        } else if (tcpModel.action == TcpAction.DeviceAction.SYSTEM_SETTING) {
+                            presenter.loadPartSettings(Constant.PART_ID)
+                        } else if (tcpModel.action == TcpAction.DeviceAction.SERVER_CHANGE) {
+                            //服务器地址变更
+                            if (tcpModel.data != null) {
+                                val json = JSONObject.parseObject(tcpModel.data.toString())
+                                val serverIp = json.getString("server_ip")
+                                val serverPort = json.getString("server_port")
+                                Log.e(TAG, "server ip:$serverIp, server port:$serverPort")
+                                CommonUtils.setUrl(activity, serverIp)
+                                CommonUtils.setUrlPort(activity, serverPort)
+                                AppTool.Time.delay(2000) {
+                                    AppUpdateHelper.restartApp(activity)
+                                }
+                            }
+                        } else if (tcpModel.action == TcpAction.DeviceAction.OPEN_DEBUG) {
+                            //打开调试
+                            AppUtil.openNetworkDebug()
+                        } else if (tcpModel.action == TcpAction.DeviceAction.REBOOT) {
+                            //设备重启
+                            AppUpdateHelper.reboot(activity)
+                        }
+                    } else if (tcpModel.action == TcpAction.DataAction.REFRESH) {
+                        Util.wakeUpAndUnlock()
+                        //重新加载数据
+                        initDevice()
+                    }  else if (tcpModel.type == TcpType.TIME) {
+                        if (tcpModel.action == TcpAction.TimeAction.SYNC) {
+                            var time = 0L
+                            var timeZone = "Asia/Shanghai"
+                            if (canParseJson(tcpModel.data.toString())) {
+                                val json = JSON.parseObject(tcpModel.data.toString())
+                                time = json.getLong("time") * 1000
+                                timeZone = json.getString("time_zone")
+                            } else {
+                                time = tcpModel.data.toString().toLong() * 1000
+                            }
+                            try {
+                                HardWareFactory.getHardTools().setTime(this, time, timeZone)
+                                Log.d("setTime", "set sys time1: $time, $timeZone")
+                            } catch (e: Exception) {
+                                //"20211213:092314"
+                                val timeStr = TimeHandle.getDateTime(time, "yyyyMMdd.HHmmss", timeZone)
+                                AppUtil.setSysTime(timeStr, timeZone)
+                                Log.d("setTime", "set sys time2: $timeStr, $timeZone")
+                            }
+                        }
+                    }
+                }
+            }
+
+            //TCP连接状态
+            Constant.EVENT_TCP_STATE -> {
+                updateTcpState()
+            }
+
+            Constant.EVENT_RESTART_APP -> {
+                Util.wakeUpAndUnlock()
+                AppUpdateHelper.restartApp(activity)
+            }
+
+            Constant.EVENT_SLEEP_START -> {
+                //启动床垫服务
+                startSLService()
+            }
+
+            Constant.EVENT_SLEEP_STOP -> {
+                //关闭床垫服务
+                stopSLService()
+            }
+
+        }
+    }
+
+
+    private fun canParseJson(str: String) : Boolean {
+        var result = false
+        try {
+            JSON.parseObject(str)
+            result=true
+        }catch (e: java.lang.Exception){
+            result=false
+        }
+        return result
+    }
+
+
+
+    private fun checkNet() {
+        /*
+        * 检查网络情况,若tcp断开连接多次且IP也是空的则网络异常,重启设备
+        * 仅对3128设备有效
+         */
+        if (Build.MODEL.equals("rk3128") || BuildConfig.flag == Constant.DEV_W_A133) {
+            Log.e("checkNet", "checkNet --> netErrCount: " + netErrCount + ", IP isEmpty: " + TextUtils.isEmpty(NetHelper.getInstance().localIP))
+            var count = SettingConfig.getNetErrResetCount(this)
+            if (!Constant.TCP_CONNECTED && TextUtils.isEmpty(NetHelper.getInstance().localIP)) {
+                netErrCount++
+            } else {
+                netErrCount = 0
+                if (count > 0) {
+                    count = 0
+                    SettingConfig.setNetErrResetCount(this, count)
+                }
+            }
+
+            if (netErrCount >= 5) {
+                //如果重启次数超过8次还是无网则不再重启
+                if (count < 8) {
+                    count++
+                    SettingConfig.setNetErrResetCount(this, count)
+                    handler.postDelayed({
+                        Log.e("reboot", "重启")
+                        AppUpdateHelper.reboot(this)
+                    }, 5000)
+                } else {
+                    runOnUiThread {
+                        WarningDialogHelper.showDialog(this@CallingbedActivity)
+                    }
+                }
+            }
+        }
+    }
+
+    private fun updateNetState() {
+        if (NetHelper.getInstance().networkType == ConnectivityManager.TYPE_WIFI) {
+            Constant.network_state = 1
+            view_title_layout_iv_wifi.visibility = View.VISIBLE
+            view_title_layout_iv_wifi.setImageResource(R.mipmap.ic_wifi_success)
+            view_title_layout_iv_ethernet.visibility = View.GONE
+
+        } else if (NetHelper.getInstance().networkType == ConnectivityManager.TYPE_ETHERNET) {
+            Constant.network_state = 2
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_success)
+            view_title_layout_iv_wifi.visibility = View.GONE
+        }  else if (NetHelper.getInstance().networkType == ConnectivityManager.TYPE_MOBILE) {
+            Constant.network_state = 3
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.net_4g)
+            view_title_layout_iv_wifi.visibility = View.GONE
+        } else {
+            Constant.network_state = 4
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_fail)
+            view_title_layout_iv_wifi.visibility = View.GONE
+        }
+        if (NetHelper.isBTConnected()) {
+            Constant.BT_state = 0
+            view_title_layout_iv_bt.visibility = View.VISIBLE
+            view_title_layout_iv_bt.setImageResource(R.mipmap.ic_bt_success)
+        } else {
+            Constant.BT_state = 1
+            view_title_layout_iv_bt.visibility = View.GONE
+        }
+    }
+
+    private fun updateTcpState() {
+        if (Constant.TCP_CONNECTED) {
+            view_title_layout_iv_tcp.setImageResource(R.mipmap.ic_tcp_success)
+            //view_title_layout_tv_point.setBackgroundResource(R.mipmap.sip_b)
+            view_title_layout_tv_sip.setTextColor(Color.DKGRAY)
+        } else {
+            view_title_layout_iv_tcp.setImageResource(R.mipmap.ic_tcp_nor)
+            //view_title_layout_tv_point.setBackgroundResource(R.mipmap.sip_h)
+            view_title_layout_tv_sip.setTextColor(Color.RED)
+        }
+    }
+
+
+    private fun updateSettings(forceSet: Boolean) {
+        val  currentTimestamp = System.currentTimeMillis()
+
+        //白天起始时间戳
+        val date = TimeHandle.getDateTime("yyyy-MM-dd")
+        val dayStartTimeStamp = TimeHandle.dateToStamp(date + " " + SettingConfig.getInitialDayTime(this) + ":00", "yyyy-MM-dd HH:mm:ss")
+        //白天结束时间戳
+        val endOfDayTimeStamp = TimeHandle.dateToStamp(date + " " + SettingConfig.getEndOfDay(this) + ":00", "yyyy-MM-dd HH:mm:ss")
+
+        val curInday = dayStartTimeStamp < currentTimestamp && currentTimestamp < endOfDayTimeStamp
+
+        if (curInday) {
+            //当前是白天并且原来不是白天
+            if (Constant.day_state != 0 || forceSet) {
+                //设置白天亮度
+                ScreenManagerUtil().setScreenBrightness(this, Math.ceil(2.54 * SettingConfig.getExtensionDaytimeBrightness(this)).toInt())
+                //设置白天系统音量和响铃音
+                VoiceManagerUtil.setSystemVoice(this, SettingConfig.getExtensionDaytimeSystemVolume(this))
+                VoiceManagerUtil.setMusicVoice(this, SettingConfig.getExtensionDaytimeSystemVolume(this))
+                view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_daylight)
+            }
+            Constant.day_state = 0
+        } else {
+            //当前是夜晚并且原来不是夜晚
+            if (Constant.day_state != 1 || forceSet) {
+                //设置晚上亮度
+                ScreenManagerUtil().setScreenBrightness(this, Math.ceil(2.54 * SettingConfig.getExtensionNightBrightness(this)).toInt())
+                //设置晚上系统音量和响铃音
+                VoiceManagerUtil.setSystemVoice(this, SettingConfig.getExtensionNightSystemVolume(this))
+                VoiceManagerUtil.setMusicVoice(this, SettingConfig.getExtensionNightSystemVolume(this))
+                view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_night)
+            }
+            Constant.day_state = 1
+        }
+    }
+
+    override fun onBackPressed() {
+        //
+    }
+
+    //广播
+    inner class TimeReceiver: BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            if (intent.action == Intent.ACTION_TIME_TICK) {
+                updateNetState()
+                if (initialized) {
+                    updateSettings(false)
+                    updateTcpState()
+                    if (Constant.LATER_RESTART && Constant.CALL_STATE == Constant.CALL_STANDBY) {
+                        Log.e(TAG, "处于延时重启,并且待机状态")
+                        AppUpdateHelper.restartApp(activity)
+                    }
+                }
+                checkNet()
+            } else if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
+                updateNetState()
+            }
+        }
+    }
+
+    fun startSLService() {
+        try {
+            SleepIntent = Intent(this, SleepService::class.java)
+            //连接服务
+            service_sl = SLService()
+            bindService(SleepIntent, service_sl!!, Context.BIND_AUTO_CREATE)
+            bindSleepService = true
+            //loopConnection()
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+        }
+    }
+
+    fun stopSLService() {
+        try {
+            SleepIntent = Intent(this, SleepService::class.java)
+            //停止并解绑服务
+            stopService(SleepIntent)
+            if (bindSleepService) {
+                unbindService(service_sl!!)
+            }
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+        }
+    }
+    inner class SLService : ServiceConnection {
+        override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
+            SleepServiceBinder = iBinder as SleepService.ServiceBinder
+        }
+
+        override fun onServiceDisconnected(componentName: ComponentName) {}
+    }
+
+
+    private fun updateLaunchApk() {
+        Thread {
+            val apkName = "launch.apk"
+            copyAssetsToDst(applicationContext, apkName, Environment.getExternalStorageDirectory().path + "/" + Environment.DIRECTORY_DOWNLOADS)
+            if (copyDone) {
+                val fileName = Environment.getExternalStorageDirectory().path + "/" + Environment.DIRECTORY_DOWNLOADS + "/" + apkName
+                //升级
+                AppUpdateHelper.rootSilenceInstall(fileName)
+                //5分钟后重启设备
+                AppTool.Time.delay(300000) {
+                    AppUpdateHelper.reboot(BaseApplication.appContext)
+                }
+            }
+        }.start()
+    }
+
+    //拷贝assets下面的文件到sd卡
+    private fun copyAssetsToDst(context: Context, fileName: String, dstPath: String) {
+        try {
+            copyDone = false
+            val file = File(dstPath)
+            if (!file.exists()) {
+                file.mkdirs()
+            }
+            val outFile = File("$dstPath/$fileName")
+            val `is` = context.assets.open(fileName)
+            val fos = FileOutputStream(outFile)
+            val buffer = ByteArray(1024)
+            var byteCount: Int
+            while (`is`.read(buffer).also { byteCount = it } != -1) {
+                fos.write(buffer, 0, byteCount)
+            }
+            fos.flush()
+            `is`.close()
+            fos.close()
+            copyDone = true
+        } catch (e: java.lang.Exception) {
+            copyDone = false
+            e.printStackTrace()
+        }
+    }
+
+}

+ 379 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/DeviceLinkageActivity.kt

@@ -0,0 +1,379 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.util.Log
+import android.view.View
+import androidx.recyclerview.widget.GridLayoutManager
+import com.clj.fastble.utils.HexUtil
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.model.NetState
+import com.inuker.bluetooth.library.Constants.REQUEST_SUCCESS
+import com.inuker.bluetooth.library.connect.listener.BluetoothStateListener
+import com.inuker.bluetooth.library.connect.options.BleConnectOptions
+import com.inuker.bluetooth.library.connect.response.BleNotifyResponse
+import com.inuker.bluetooth.library.connect.response.BleWriteResponse
+import com.inuker.bluetooth.library.receiver.listener.BluetoothBondListener
+import com.inuker.bluetooth.library.search.SearchRequest
+import com.inuker.bluetooth.library.search.SearchResult
+import com.inuker.bluetooth.library.search.response.SearchResponse
+import com.inuker.bluetooth.library.utils.BluetoothLog
+import com.inuker.bluetooth.library.utils.ByteUtils
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.adapter.DeviceLinAdapter
+import com.wdkl.app.ncs.callingbed.databinding.DeviceLinLayBinding
+import com.wdkl.app.ncs.callingbed.dialog.DeviceLinkDialogHelper
+import com.wdkl.app.ncs.callingbed.dialog.DeviceLinkSleepDialogHelper
+import com.wdkl.app.ncs.callingbed.dialog.WifiSetDialogHelper
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.sleep.SleepDataParse
+import com.wdkl.app.ncs.callingbed.utils.ClientManager
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedDeviceLinkageActivityContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedDeviceLinkagePresenter
+import com.wdkl.ncs.android.middleware.model.vo.DeviceLinVo
+import kotlinx.android.synthetic.main.device_lin_lay.*
+import kotlinx.android.synthetic.main.view_title_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.util.*
+import kotlin.collections.ArrayList
+
+
+/**
+ * 联动设备界面
+ * */
+@Router(path = "/callingbed/link")
+class DeviceLinkageActivity : BaseActivity<BedDeviceLinkagePresenter, DeviceLinLayBinding>(), BedDeviceLinkageActivityContract.View ,DeviceLinAdapter.OnItemClickListener{
+
+    private val TAG = "DeviceLinkageActivity"
+
+    private lateinit var deviceMenuAdapter : DeviceLinAdapter
+
+    private var allOrders = ArrayList<DeviceLinVo>()
+
+    val mService: UUID =UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb")
+    //手机发往设备
+    val mCharacter1: UUID =UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb")
+    //设备发往手机
+    val mCharacter2: UUID =UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb")
+
+    lateinit var inst: DeviceLinkageActivity
+
+    var isbtopen :Boolean =false
+    override fun getLayId(): Int {
+        return R.layout.device_lin_lay
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        inst =this
+        ClientManager.getClient().registerBluetoothStateListener(mBluetoothStateListener);
+        showui()
+        val layoutManager = GridLayoutManager(activity, 3)
+        dv_lin_recycler.visibility = View.VISIBLE
+        dv_lin_recycler.layoutManager = layoutManager
+
+        deviceMenuAdapter = DeviceLinAdapter(activity, allOrders)
+        deviceMenuAdapter.setOnItemClickListener(this)
+        dv_lin_recycler.adapter = deviceMenuAdapter
+
+        if (Constant.FRAME_ID!=-1){
+            presenter.loadDevicesList(Constant.FRAME_ID)
+        }
+    }
+
+    override fun bindEvent() {
+        //返回上一层
+        view_title_layout_return.setOnClickListener {
+            view_title_layout_img.visibility = View.GONE
+            view_title_layout_tv_no.visibility =View.GONE
+            finish()
+        }
+
+
+
+    }
+
+    override fun destory() {
+        ClientManager.getClient().unregisterBluetoothStateListener(mBluetoothStateListener);
+    }
+
+    private fun searchDevice() {
+
+        val request = SearchRequest.Builder()
+                .searchBluetoothLeDevice(5000, 2).build()
+
+        ClientManager.getClient().search(request, mSearchResponse)
+
+
+    }
+    //蓝牙是否打开的回掉
+    private val mBluetoothStateListener: BluetoothStateListener = object : BluetoothStateListener() {
+        override fun onBluetoothStateChanged(openOrClosed: Boolean) {
+            if (openOrClosed){
+                searchDevice()
+            }
+
+        }
+    }
+    //蓝牙配对状态的回调
+    private val mBluetoothBondListener: BluetoothBondListener = object : BluetoothBondListener() {
+        override fun onBondStateChanged(mac: String, bondState: Int) {
+            // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
+        }
+    }
+
+
+
+  
+    private val mSearchResponse: SearchResponse = object : SearchResponse {
+        override fun onSearchStarted() {
+            BluetoothLog.w("MainActivity.onSearchStarted")
+           //扫描中
+            pbar.visibility = View.VISIBLE
+        }
+
+        override fun onDeviceFounded(device: SearchResult) {
+            BluetoothLog.v(TAG + device.name)
+            if (device.name.equals("LZ-OTA " + bt_name)){
+                pbar.visibility = View.GONE
+                isbtopen =true
+                bt_mac = device.address
+                //搜索到了绑定设备 开始配对
+                val options = BleConnectOptions.Builder()
+                        .setConnectRetry(3)
+                        .setConnectTimeout(20000)
+                        .setServiceDiscoverRetry(3)
+                        .setServiceDiscoverTimeout(10000)
+                        .build()
+
+                ClientManager.getClient().connect(device.getAddress(), options) { code, profile ->
+                    BluetoothLog.v(String.format("profile:\n%s", profile))
+                    if (code == REQUEST_SUCCESS) {
+                        //连接成功
+                        DeviceLinkSleepDialogHelper.showDialog(inst, object : DeviceLinkSleepDialogHelper.ClickListener {
+                            override fun onClick(name: String?, Password: String?) {
+                                if (name != null && Password != null) {
+                                    pbar.visibility = View.VISIBLE
+                                    DeviceLinkSleepDialogHelper.dismissCallDialog()
+                                    sendMsg(name, Password)
+
+                                }
+
+                            }
+                        })
+                    }else{
+                        //连接失败
+                        WifiSetDialogHelper.showDialog(activity,4)
+                    }
+
+                }
+
+            }
+//            BluetoothLog.w("MainActivity.onDeviceFounded " + device.device.getAddress());
+
+//                Beacon beacon = new Beacon(device.scanRecord);
+//                BluetoothLog.v(String.format("beacon for %s\n%s", device.getAddress(), beacon.toString()));
+
+//                BeaconItem beaconItem = null;
+//                BeaconParser beaconParser = new BeaconParser(beaconItem);
+//                int firstByte = beaconParser.readByte(); // 读取第1个字节
+//                int secondByte = beaconParser.readByte(); // 读取第2个字节
+//                int productId = beaconParser.readShort(); // 读取第3,4个字节
+//                boolean bit1 = beaconParser.getBit(firstByte, 0); // 获取第1字节的第1bit
+//                boolean bit2 = beaconParser.getBit(firstByte, 1); // 获取第1字节的第2bit
+//                beaconParser.setPosition(0); // 将读取起点设置到第1字
+        }
+
+        override fun onSearchStopped() {
+            BluetoothLog.w("MainActivity.onSearchStopped")
+            //停止了
+            pbar.visibility = View.GONE
+            if (isbtopen){
+                isbtopen =false
+            }else{
+                WifiSetDialogHelper.showDialog(activity,3)
+            }
+
+
+        }
+
+        override fun onSearchCanceled() {
+            BluetoothLog.w("MainActivity.onSearchCanceled")
+            //取消了
+            pbar.visibility = View.GONE
+            if (isbtopen){
+                isbtopen =false
+            }else{
+                WifiSetDialogHelper.showDialog(activity,3)
+            }
+
+        }
+    }
+
+    private fun showui(){
+        view_title_layout_tv_hospital_name.setText(R.string.str_back)
+        view_title_layout_img.visibility = View.VISIBLE
+        view_title_layout_tv_no.visibility =View.VISIBLE
+        view_title_layout_tv_no.setText(R.string.device_linkage)
+    }
+
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+//        ClientManager.getClient().unnotify(bt_mac, mService, mCharacter2, null)
+        if(bt_mac!=""){
+            ClientManager.getClient().disconnect(bt_mac)
+        }
+        super.onStop()
+    }
+
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        when (messageEvent.getType()) {
+            Constant.EVENT_FINISHh -> {
+                finish()
+            }
+        }
+    }
+
+    override fun setDevicesList(advices: ArrayList<DeviceLinVo>) {
+        if (advices.size>0){
+            dv_lin_emptyImageView.visibility =View.GONE
+            allOrders =advices
+            deviceMenuAdapter.updateData(allOrders)
+        }
+    }
+
+    override fun onNoneNet() {
+        dv_lin_emptyImageView.visibility =View.VISIBLE
+    }
+
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+        dv_lin_emptyImageView.visibility =View.VISIBLE
+    }
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    //开始获取数据
+    override fun start() {
+        //
+    }
+
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+
+    var bt_mac : String=""
+    var bt_name : String=""
+
+    //发送数据
+    private fun sendMsg(name: String, Password: String){
+        ClientManager.getClient().notify(bt_mac, mService, mCharacter2, mNotifyRsp)
+//        //测试数据
+//        val str ="CD0E0004"
+//        val signData = HexUtil.hexStringToBytes(str)
+        //组装数据
+        val signData = SleepDataParse.parseValue4(name, Password)
+        Log.d(TAG, "发送配网数据: " + HexUtil.formatHexString(signData, false))
+        val maxPacketSize = 20 // 最大包大小
+        if (signData.size <= maxPacketSize){
+            ClientManager.getClient().write(bt_mac, mService, mCharacter1, signData, mWriteRsp)
+            Log.d(TAG, "总数据: " + HexUtil.formatHexString(signData, false))
+        }else{
+            // 数据需要分包发送
+            val numPackets = Math.ceil(signData.size.toDouble() / maxPacketSize).toInt()
+            for (i in 0 until numPackets) {
+                val start = i * maxPacketSize
+                val end = Math.min(signData.size, start + maxPacketSize)
+                val packetData = signData.copyOfRange(start, end)
+                ClientManager.getClient().write(bt_mac, mService, mCharacter1, packetData, mWriteRsp)
+                Log.d(TAG, "分包数据: " + HexUtil.formatHexString(packetData, false))
+                // 可以在这里添加延时,确保按顺序发送分包
+                 Thread.sleep(100) // 100 毫秒延时
+            }
+        }
+    }
+
+    private val mWriteRsp = BleWriteResponse { code ->
+        if (code == REQUEST_SUCCESS) {
+//            showMessage("发送成功")
+            BluetoothLog.v(TAG + "发送成功")
+        } else {
+//            showMessage("发送失败")
+            BluetoothLog.v(TAG + "发送失败")
+        }
+    }
+
+    private val mNotifyRsp: BleNotifyResponse = object : BleNotifyResponse {
+        override fun onNotify(service: UUID, character: UUID, value: ByteArray) {
+            if (service == mService && character == mCharacter2) {
+                Log.d(TAG, String.format("%s", ByteUtils.byteToString(value)))
+                BluetoothLog.v(TAG + "收到通知")
+                var substring = String.format("%s", ByteUtils.byteToString(value)).substring(8, 10)
+                BluetoothLog.v(TAG + substring)
+                pbar.visibility = View.GONE
+                if (substring.equals("00")){
+                    WifiSetDialogHelper.showDialog(activity,1)
+                }else if (substring.equals("01")){
+                    WifiSetDialogHelper.showDialog(activity,2)
+                }else{
+                    BluetoothLog.v(TAG + "收到其他通知")
+                }
+            }
+        }
+
+        override fun onResponse(code: Int) {
+            if (code == REQUEST_SUCCESS) {
+                BluetoothLog.v(TAG + "开启通知")
+            } else {
+                BluetoothLog.v(TAG + "开启通知失败")
+            }
+        }
+    }
+
+
+    override fun onItemClick(view: View, keyId: Int) {
+        //增加一个弹窗 显示设备信息
+        DeviceLinkDialogHelper.showDialog(activity, allOrders.get(keyId), object : DeviceLinkDialogHelper.ClickListener {
+            override fun onClick(bedVO: String?) {
+                bt_name = bedVO.toString()
+                DeviceLinkDialogHelper.dismissCallDialog()
+                //扫码蓝牙
+                if (ClientManager.getClient().isBluetoothOpened) {
+                    searchDevice()
+                } else {
+                    showMessage(getString(R.string.ble_device_5))
+                    ClientManager.getClient().openBluetooth()
+                }
+
+            }
+        })
+
+    }
+
+}

+ 226 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/DeviceSystemActivity.kt

@@ -0,0 +1,226 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.content.res.Configuration
+import android.os.Handler
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.RadioGroup
+import android.widget.Toast
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.CallingbedDeviceSysBinding
+import com.wdkl.app.ncs.callingbed.dialog.CallConfigDialogHelper
+import com.wdkl.app.ncs.callingbed.dialog.SystemDialogHelper
+import com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.core.locale.LocaleMangerUtils
+import com.wdkl.ncs.android.lib.core.locale.SettingConfigNew
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedTextActivityContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedTextActivityPresenter
+import kotlinx.android.synthetic.main.callingbed_device_sys.*
+import kotlinx.android.synthetic.main.view_title_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+/**
+ * 设备配置界面
+ * */
+class DeviceSystemActivity : BaseActivity<BedTextActivityPresenter, CallingbedDeviceSysBinding>(), BedTextActivityContract.View , View.OnClickListener{
+
+    private val TAG = "DeviceSystemActivity"
+
+    private var selectIndex: Int = 0
+    private var selectIndex1: Int = 0
+
+    override fun getLayId(): Int {
+        return R.layout.callingbed_device_sys
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        showui()
+        val originIndex1 = SettingConfig.getScene(activity)
+        val adapter1 = ArrayAdapter.createFromResource(activity,
+                R.array.device_list, R.layout.spinner_item)
+        adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+        device_sys_ed_1.setAdapter(adapter1)
+        device_sys_ed_1.setSelection(originIndex1)
+
+        device_sys_ed_1.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
+            override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
+                Log.d("languageId", "pos: $position")
+                selectIndex1 = position
+            }
+
+            override fun onNothingSelected(parent: AdapterView<*>?) {}
+        })
+
+
+        val originIndex = LocaleMangerUtils.getCurrentLocaleIndex()
+        val adapter = ArrayAdapter.createFromResource(activity,
+                R.array.language_list, R.layout.spinner_item)
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+        device_sys_ed_2.setAdapter(adapter)
+        device_sys_ed_2.setSelection(originIndex)
+        device_sys_ed_2.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
+            override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
+                Log.d("languageId", "pos: $position, originIndex: $originIndex")
+                selectIndex = position
+            }
+
+            override fun onNothingSelected(parent: AdapterView<*>?) {}
+        })
+
+
+//        if(SettingConfigNew.getLanguageId(activity)==0){
+//            device_sys_ed_1.setHint(R.string.language_list_1)
+//        }else if (SettingConfigNew.getLanguageId(activity)==1){
+//            device_sys_ed_1.setHint(R.string.language_list_2)
+//        }else if (SettingConfigNew.getLanguageId(activity)==2){
+//            device_sys_ed_1.setHint(R.string.language_list_3)
+//        }else if (SettingConfigNew.getLanguageId(activity)==3){
+//            device_sys_ed_1.setHint(R.string.language_list_4)
+//        }else if (SettingConfigNew.getLanguageId(activity)==4){
+//            device_sys_ed_1.setHint(R.string.language_list_5)
+//        }
+
+        val mode = SettingConfigNew.getLanguageMode(activity)
+        if (mode == 0) {
+            device_sys_radio_language_on.setChecked(true)
+        } else {
+            device_sys_radio_language_off.setChecked(true)
+        }
+
+
+        val orientation = resources.configuration.orientation
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            // 当前是横屏
+            device_sys_radio_window_on.setChecked(true)
+        } else {
+            // 当前是竖屏
+            device_sys_radio_window_off.setChecked(true)
+        }
+
+        device_sys_save_settings_tv.setOnClickListener(this)
+        device_sys_language_settings_tv.setOnClickListener(this)
+        device_sys_system_settings_tv.setOnClickListener(this)
+        device_sys_software_and_information_tv.setOnClickListener(this)
+    }
+
+    override fun bindEvent() {
+        //返回上一层
+        view_title_layout_return.setOnClickListener {
+            view_title_layout_img.visibility = View.GONE
+            view_title_layout_tv_no.visibility =View.GONE
+            finish()
+        }
+
+        device_sys_group_sip.setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener { group, checkedId ->
+            if (checkedId == R.id.device_sys_radio_language_on) {
+                SettingConfigNew.setLanguageMode(activity, 0)
+            } else {
+                SettingConfigNew.setLanguageMode(activity, 1)
+            }
+        })
+
+    }
+
+    override fun destory() {
+
+    }
+
+
+
+    private fun showui(){
+        view_title_layout_tv_hospital_name.setText(R.string.str_back)
+        view_title_layout_img.visibility = View.VISIBLE
+        view_title_layout_tv_no.visibility =View.VISIBLE
+        view_title_layout_tv_no.setText(R.string.device_config)
+    }
+
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+
+    }
+
+
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+
+    }
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    //开始获取数据
+    override fun start() {
+        //
+    }
+
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+
+    override fun onClick(p0: View?) {
+        when (p0?.id) {
+            //保存设置
+            R.id.device_sys_save_settings_tv -> {
+                SettingConfigNew.setLanguageId(activity, selectIndex)
+                SettingConfig.setMIC(activity, selectIndex1)
+                Toast.makeText(activity, "restart now...", Toast.LENGTH_LONG).show()
+                Handler().postDelayed({ AppUpdateHelper.restartApp(activity) }, 3000)
+            }
+            //通话设置
+            R.id.device_sys_language_settings_tv -> {
+                if (BuildConfig.flag.equals(Constant.DEV_W_A133)) {
+                    CallConfigDialogHelper.showDialog(activity)
+                } else {
+                    showMessage(R.string.device_not_support)
+                }
+
+            }
+            //进入设置
+            R.id.device_sys_system_settings_tv -> {
+                SystemDialogHelper.showDialog(activity, 2)
+            }
+            //关于主机
+            R.id.device_sys_software_and_information_tv -> {
+
+            }
+        }
+    }
+}

+ 277 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/SleepMonitoringActivity.kt

@@ -0,0 +1,277 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentTransaction
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil
+import com.wdkl.app.ncs.callingbed.databinding.SleepActivityBinding
+import com.wdkl.app.ncs.callingbed.fragment.SleepDataTableFragment
+import com.wdkl.app.ncs.callingbed.fragment.SleepGraphOfCurveFragment
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedSignFragmentContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedSignFragmentPresenter
+import com.wdkl.ncs.android.middleware.model.vo.SingDataBean
+import kotlinx.android.synthetic.main.sleep_activity.*
+import kotlinx.android.synthetic.main.view_title_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+/**
+ * 睡眠检测
+ * */
+@Router(path = "/callingbed/sleep")
+class SleepMonitoringActivity : BaseActivity<BedSignFragmentPresenter, SleepActivityBinding>(), BedSignFragmentContract.View {
+    private val TAG = "SleepMonitoringActivity"
+    private var infoFragment: Fragment? = null
+
+    var type:String=""
+    override fun getLayId(): Int {
+        return R.layout.sleep_activity
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    override fun init() {
+        showui()
+        //默认显示曲线图
+        val fragment = SleepGraphOfCurveFragment()
+        var bundle = Bundle()
+        bundle.putString("states", type)
+        fragment.arguments = bundle
+        addCallFragment(fragment)
+    }
+
+    override fun destory() {
+
+    }
+
+
+
+    private fun addCallFragment(fragment: Fragment) {
+        supportFragmentManager.inTransaction {
+            if (infoFragment!=null){
+                remove(infoFragment!!)
+            }
+            infoFragment = fragment
+            updateLeftBtState()
+            add(R.id.activity_sleep, fragment)
+        }
+    }
+    private fun updateLeftBtState() {
+        sleep_previous_button.setBackgroundResource(R.drawable.shape_main_bt_bg)
+        sleep_previous_button.setTextColor(getResources().getColor(R.color.text_name_color))
+
+        sleep_next_button.setBackgroundResource(R.drawable.shape_main_bt_bg)
+        sleep_next_button.setTextColor(getResources().getColor(R.color.text_name_color))
+
+        // 判断当前显示的Fragment是哪个
+        when (infoFragment) {
+            is SleepDataTableFragment -> {
+                //报表
+                sleep_next_button.setBackgroundResource(R.drawable.shape_main_hos_txt_bg)
+                sleep_next_button.setTextColor(getResources().getColor(R.color.white))
+            }
+            is SleepGraphOfCurveFragment -> {
+                //折现图
+                sleep_previous_button.setBackgroundResource(R.drawable.shape_main_hos_txt_bg)
+                sleep_previous_button.setTextColor(getResources().getColor(R.color.white))
+
+            }
+
+
+        }
+
+    }
+    override fun bindEvent() {
+        //返回
+        view_title_layout_return.setOnClickListener {
+            finish()
+        }
+
+        //曲线图
+        sleep_previous_button.setOnClickListener {
+            val fragment = SleepGraphOfCurveFragment()
+            var bundle = Bundle()
+            bundle.putString("states", type)
+            fragment.arguments = bundle
+            addCallFragment(fragment)
+
+        }
+
+
+        //数据列表
+        sleep_next_button.setOnClickListener {
+            val fragment = SleepDataTableFragment()
+            var bundle = Bundle()
+            bundle.putString("state", type)
+            fragment.arguments = bundle
+            addCallFragment(fragment)
+        }
+
+    }
+
+    private fun showui(){
+        view_title_layout_tv_hospital_name.setText(R.string.str_back)
+        view_title_layout_img.visibility = View.VISIBLE
+        view_title_layout_tv_no.visibility = View.VISIBLE
+        view_title_layout_tv_no.setText(R.string.str_sleep_monitor)
+
+
+        sleep_bed_name.text =Constant.FJ_NAME
+        sleep_bed_sex.text =Constant.FJ_SEX
+        sleep_bed_age.text =Constant.FJ_AGE
+        if ( Constant.Sleep_TCP_CONNECTED){
+            sleep_bed_wifi.setText(R.string.str_device_online)
+        }else{
+            sleep_bed_wifi.setText(R.string.str_device_offline)
+        }
+
+
+        //网络图标
+        if ( Constant.network_state == 1){
+            view_title_layout_iv_wifi.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.visibility = View.GONE
+            view_title_layout_iv_wifi.setImageResource(R.mipmap.ic_wifi_success)
+        }else if ( Constant.network_state == 2){
+            view_title_layout_iv_wifi.visibility = View.GONE
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_success)
+        }else{
+            view_title_layout_iv_wifi.visibility = View.GONE
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_fail)
+        }
+        //蓝牙图标
+        if ( Constant.BT_state == 0){
+            view_title_layout_iv_bt.setImageResource(R.mipmap.ic_bt_success)
+        }
+        //白天/黑夜
+        if (Constant.day_state == 0){
+            view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_daylight)
+        }else{
+            view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_night)
+        }
+        view_title_layout_iv_tcp.setImageResource(R.mipmap.ic_tcp_success)
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+    //心率
+    var heartRate :Int=0
+    //读取呼吸率
+    var breathingRate  :Int=0
+    //状态
+    var status_int  :Int=0
+    //状态
+    var status  :String=""
+    //电池电量
+    var batteryLevel  : String=""
+    // 读取监测带 SN
+    var monitorSN  : String=""
+
+    var slepp_data :String=""
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        if (Constant.EVENT_FINISHh == messageEvent.type) {
+            finish()
+        }else   if (Constant.EVENT_SLEEP_DATA == messageEvent.type) {
+            if (messageEvent.slepp_data!=null){
+                slepp_data= messageEvent.slepp_data
+                SleppDataDataParsing(slepp_data)
+            }
+
+        }
+
+
+
+    }
+    //床垫数据解析
+    private fun SleppDataDataParsing(data: String) {
+        heartRate = BluetoothUtil.hexToDecimal(data.substring(0, 2))
+        breathingRate = BluetoothUtil.hexToDecimal(data.substring(2, 4))
+        status_int = BluetoothUtil.hexToDecimal(data.substring(4, 6))
+        if( status_int == 3){
+            status = getString(R.string.str_in_bed)
+        }else  if( status_int == 4){
+            status = getString(R.string.str_out_bed)
+        }else  if( status_int == 5){
+            status = getString(R.string.str_snore)
+        }else  if( status_int == 6){
+            status = getString(R.string.str_body_move)
+        }
+
+//        sleep_bed_type.text =" 心率:"+heartRate+" 次/分 呼吸"+breathingRate+"次/分 当前状态:"+status
+
+        sleep_bed_type.text = getString(R.string.str_sleep_status, status)
+        if (data.substring(6, 8).equals("64")){
+            batteryLevel ="100%"
+        }
+        if(BuildConfig.sleep_type == "1"){
+            type = data.substring(8, 20)
+            monitorSN="SN:"+data.substring(8, 20)
+            if (sleep_bed_sn.text.equals("")){
+                sleep_bed_sn.text =monitorSN
+            }
+        }
+
+
+
+
+    }
+    override fun showsigns(advices: ArrayList<SingDataBean>) {
+//        if(advices !=null){
+//            adapter.updateData(advices)
+//        }
+
+
+    }
+
+    override fun onNoNet() {
+
+    }
+
+
+    override fun onError(message: String, type: Int) {
+
+    }
+
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    override fun start() {
+
+    }
+
+    override fun networkMonitor(state: NetState) {
+
+    }
+
+
+    inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
+        beginTransaction().func().commitAllowingStateLoss()
+    }
+
+}

+ 366 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/SystemActivity.kt

@@ -0,0 +1,366 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.app.Activity
+import android.bluetooth.BluetoothAdapter
+import android.content.Intent
+import android.os.Build
+import android.view.View
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.CallingbedSettingMainBinding
+import com.wdkl.app.ncs.callingbed.dialog.*
+import com.wdkl.app.ncs.callingbed.helper.NetHelper
+import com.wdkl.app.ncs.callingbed.helper.UpdateTipsDialogHelper
+import com.wdkl.app.ncs.callingbed.helper.Utils
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig
+
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.utils.EcodeHelper
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.api.UrlManager
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingdoor.SystemActivityContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingdoor.SystemActivityPresenter
+import com.wdkl.ncs.android.middleware.model.dos.AppVersionDO
+import com.wdkl.ncs.android.middleware.tcp.enums.DeviceTypeEnum
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import kotlinx.android.synthetic.main.callingbed_setting_main.*
+
+import kotlinx.android.synthetic.main.view_title_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+class SystemActivity : BaseActivity<SystemActivityPresenter, CallingbedSettingMainBinding>(), SystemActivityContract.View {
+    private val TAG = "SystemActivity"
+    val QR_CODE_PATH = "http://m.wdklian.com/care/apk/care.user?type=NCS_DEVICE"
+    private var clickTime: Long = 0
+    private var clickTimes: Int = 1
+
+    private var bluetoothAdapter: BluetoothAdapter? = null
+    private val REQUEST_CODE_ENABLE_BT = 111
+
+    override fun getLayId(): Int {
+        return R.layout.callingbed_setting_main
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        showui()
+    }
+
+    override fun bindEvent() {
+        //服务器设置
+        settings_main_1_ll.setOnClickListener {
+            ServicesDialogHelper.showDialog(activity, object : ServicesDialogHelper.ClickListener {
+                override fun onClick(bedVO: String?) {
+                    setfuq()
+                }
+            })
+        }
+        //网络设置
+        settings_main_2_ll.setOnClickListener {
+            NetworkDialogHelper.showDialog(activity)
+        }
+
+        //设备配置
+        settings_main_top_3_ll.setOnClickListener {
+            val intent = Intent()
+            intent.setClass(activity, DeviceSystemActivity::class.java)
+            activity.startActivity(intent)
+        }
+
+        //进入调试
+        settings_main_3_ll.setOnClickListener {
+
+        }
+        //版本更新
+        settings_main_4_ll.setOnClickListener {
+            UpdataDialogHelper.showDialog(activity, object : UpdataDialogHelper.ClickListener {
+                override fun onClick() {
+                    if (Constant.PART_ID != null) {
+                        if ("rk3128".equals(Build.MODEL)) {
+                            presenter.getAppVersion(Constant.PART_ID, 204)
+                        } else {
+                            presenter.getAppVersion(Constant.PART_ID, 104)
+                        }
+                    } else {
+                        showMessage("null part id")
+                    }
+                }
+            })
+        }
+        //重启设备
+        settings_main_5_ll.setOnClickListener {
+            RebootDialogHelper.showDialog(activity)
+        }
+        //返回上一层
+        view_title_layout_return.setOnClickListener {
+            view_title_layout_img.visibility = View.GONE
+            view_title_layout_tv_no.visibility = View.GONE
+            finish()
+        }
+
+        setting_qr_code.setOnClickListener {
+            val time = System.currentTimeMillis()
+            if (time - clickTime < 1500) {
+                clickTimes++
+            } else {
+                clickTimes = 1
+            }
+
+            if (clickTimes > 15) {
+                showMessage("enable status bar")
+                Utils.hideStatusBar(activity, false)
+                clickTimes = 1
+            }
+            clickTime = time
+        }
+
+        switch_bluetooth.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                if (checkBluetoothPermission()) {
+                    //开启蓝牙扫描
+                    showMessage(R.string.enable_bt_gateway)
+                    SettingConfig.setBluetoothGatewayOn(activity, true)
+                    EventBus.getDefault().post(MessageEvent("ble_on", Constant.EVENT_BLE_START))
+                } else {
+                    showMessage(R.string.enable_bluetooth)
+                }
+            } else {
+                showMessage(R.string.disable_bt_gateway)
+                SettingConfig.setBluetoothGatewayOn(activity, false)
+                EventBus.getDefault().post(MessageEvent("ble_off", Constant.EVENT_BLE_STOP))
+            }
+        }
+
+        switch_433.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                SettingConfig.set433GatewayOn(activity, true)
+                EventBus.getDefault().post(MessageEvent("433_on", Constant.EVENT_433_START))
+
+            } else {
+                SettingConfig.set433GatewayOn(activity, false)
+                EventBus.getDefault().post(MessageEvent("433_off", Constant.EVENT_433_STOP))
+            }
+        }
+
+        switch_sleep.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                SettingConfig.setSLEEPGatewayOn(activity, true)
+                EventBus.getDefault().post(MessageEvent("sleep_on", Constant.EVENT_SLEEP_START))
+
+            } else {
+                SettingConfig.setSLEEPGatewayOn(activity, false)
+                EventBus.getDefault().post(MessageEvent("sleep_off", Constant.EVENT_SLEEP_STOP))
+            }
+        }
+    }
+
+    private fun checkBluetoothPermission(): Boolean {
+        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
+        if (bluetoothAdapter != null) {
+            if (!bluetoothAdapter!!.isEnabled()) {
+                val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
+                startActivityForResult(enableBtIntent, REQUEST_CODE_ENABLE_BT)
+                return false
+            } else {
+                return true
+            }
+        }
+
+        return false
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        if (resultCode == Activity.RESULT_OK) {
+            if (requestCode == REQUEST_CODE_ENABLE_BT) {
+                EventBus.getDefault().post(MessageEvent("ble_on", Constant.EVENT_BLE_START))
+            }
+        }
+        super.onActivityResult(requestCode, resultCode, data)
+    }
+
+    override fun destory() {
+
+    }
+
+    fun setfuq(){
+        settings_main_10_tx.text= CommonUtils.getUrl(this)
+        showMessage(R.string.reboot_register)
+    }
+
+    private fun showui(){
+
+        if (BuildConfig.is_mom.toBoolean()){
+            view_title_layout_tv_hospital_name.setText(R.string.str_back)
+            view_title_layout_img.visibility = View.VISIBLE
+            view_title_layout_tv_no.visibility =View.GONE
+        }else{
+            view_title_layout_tv_hospital_name.setText(R.string.str_back)
+            view_title_layout_img.visibility = View.VISIBLE
+            view_title_layout_tv_no.visibility =View.VISIBLE
+            view_title_layout_tv_no.setText(R.string.str_device_info)
+        }
+
+        //网络图标
+        if ( Constant.network_state == 1){
+            view_title_layout_iv_wifi.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.visibility = View.GONE
+            view_title_layout_iv_wifi.setImageResource(R.mipmap.ic_wifi_success)
+        }else if ( Constant.network_state == 2){
+            view_title_layout_iv_wifi.visibility = View.GONE
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_success)
+        }else if ( Constant.network_state == 2){
+            view_title_layout_iv_wifi.visibility = View.GONE
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.net_4g)
+        }else{
+            view_title_layout_iv_wifi.visibility = View.GONE
+            view_title_layout_iv_ethernet.visibility = View.VISIBLE
+            view_title_layout_iv_ethernet.setImageResource(R.mipmap.ic_ethernet_fail)
+        }
+        //蓝牙图标
+        if ( Constant.BT_state == 0){
+            view_title_layout_iv_bt.setImageResource(R.mipmap.ic_bt_success)
+        }
+        //白天/黑夜
+        if (Constant.day_state == 0){
+            view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_daylight)
+        }else{
+            view_title_layout_iv_day_night.setImageResource(R.mipmap.ic_night)
+        }
+        view_title_layout_iv_tcp.setImageResource(R.mipmap.ic_tcp_success)
+        //设置二维码
+        setQrcode()
+
+        val netInfo = NetHelper.getNetInfo(activity)
+        //设备id
+        settings_main_6_tx.text =  ""+Constant.DEVICE_ID
+        //设备ip
+        settings_main_7_tx.text = NetHelper.getInstance().localIP
+
+        if (netInfo != null) {
+            //设备网关
+            settings_main_8_tx.text = netInfo.gateway
+            //设备dns
+            settings_main_9_tx.text = netInfo.dns1 + "/" + netInfo.netMask
+        }
+        //服务器地址
+        val buildUrl = UrlManager.build()
+        settings_main_10_tx.text=   buildUrl.buyer.substringAfterLast("//").substringBefore(":")
+        //语音id
+        settings_main_11_tx.text= Constant.SIP_ID
+        //语音类型 ??
+        if(SettingConfig.getSipEnabled(activity)){
+            settings_main_12_tx.text= "sip"
+        }else{
+            settings_main_12_tx.text= "webrtc"
+        }
+
+
+        //语音服务器
+        settings_main_13_tx.text= "${Constant.SIP_ID}@${Constant.sip_ip}:${Constant.sip_port}"
+        //app版本
+        settings_main_14_tx.text =  BuildConfig.VERSION_NAME + "_" + BuildConfig.VERSION_CODE + "_" + Build.MODEL
+        //发布日期
+        settings_main_15_tx.text =  BuildConfig.BUILD_TIME
+//        activation_zcm.text=  Constant.DEVICE_REGISTER_ID
+
+        switch_bluetooth.isChecked = SettingConfig.getBluetoothGatewayOn(activity)
+
+        switch_433.isChecked = SettingConfig.get433GatewayOn(activity)
+
+        switch_sleep.isChecked = SettingConfig.getSLEEPGatewayOn(activity)
+    }
+    //设置二维码
+    private fun setQrcode(){
+        Thread{
+            //val logoBitmap = BitmapFactory.decodeResource(resources, R.mipmap.erlogo)
+            var builder = StringBuilder()
+            builder.append(QR_CODE_PATH)
+            builder.append("&code=")
+            builder.append(Constant.DEVICE_CODE)
+            builder.append("&mac=")
+            builder.append(Constant.DEVICE_REGISTER_ID)
+            builder.append("&model=")
+            builder.append(Constant.DEVICE_MODEL)
+            builder.append("&hard_ver=")
+            builder.append(Constant.DEVICE_HARD_VER)
+            builder.append("&soft_ver=")
+            builder.append(Constant.DEVICE_SOFT_VER)
+            builder.append("&device_type=")
+            builder.append(DeviceTypeEnum.DIGIT_BED_DEVICE.value())
+            builder.append("&device_name=")
+            builder.append(DeviceTypeEnum.DIGIT_BED_DEVICE.typeName())
+            val code = EcodeHelper().createQRImage(builder.toString(), 200, null)
+            activity.runOnUiThread {
+                setting_qr_code?.setImageBitmap(code)
+            }
+        }.start()
+    }
+
+    override fun loadAppVersion(appInfo: AppVersionDO) {
+        var version = BuildConfig.VERSION_CODE.toInt()
+        if ( version< appInfo.versionNo) {
+            Constant.APP_UPDATING = true
+            Constant.APP_PATH = appInfo.appPath
+            UpdateTipsDialogHelper.showDialog(activity)
+
+        } else {
+            showMessage(R.string.update_no_required)
+        }
+    }
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        if (Constant.EVENT_FINISHh == messageEvent.type) {
+            finish()
+
+        }
+    }
+    override fun onNoNet() {
+
+    }
+
+    //数据加载错误
+    override fun onError(message: String, type: Int) {
+
+    }
+    //数据加载完成
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    //开始获取数据
+    override fun start() {
+        //
+    }
+
+    //网络监听
+    override fun networkMonitor(state: NetState) {
+        state.filter(onMobile = {
+
+        }, onWifi = {
+
+        }, offline = {
+
+        })
+    }
+}

+ 184 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/WebviewActivity.kt

@@ -0,0 +1,184 @@
+package com.wdkl.app.ncs.callingbed.activity
+
+import android.graphics.Bitmap
+import android.os.Build
+import android.text.TextUtils
+import android.util.Log
+import android.view.View
+import android.webkit.WebChromeClient
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.WebciewLayBinding
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.ncs.android.lib.base.BaseActivity
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedWebViewActivityContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedWebviewActivityPresenter
+import kotlinx.android.synthetic.main.webciew_lay.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+
+@Router(path = "/callingbed/webview")
+class WebviewActivity :BaseActivity<BedWebviewActivityPresenter, WebciewLayBinding>(), BedWebViewActivityContract.View{
+    private val TAG = "WebviewActivity"
+    override fun getLayId(): Int {
+        // 解决共用system uid时报
+        // Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes 错误
+        val uid = android.os.Process.myUid()
+        if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
+            hookWebView()
+        }
+
+        return R.layout.webciew_lay
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        val settings: WebSettings = webview.settings
+        webviewSetting(settings);
+        val name = intent.getStringExtra("name") ?: ""
+        if (name!=null){
+            top_title_tv.setText(name)
+        }
+        val url = intent.getStringExtra("url") ?: ""
+        val key = intent.getStringExtra("key") ?: ""
+
+        if (!TextUtils.isEmpty(url)){
+            if (!TextUtils.isEmpty(key)) {
+                val result = key.replace("&amp;", "&")
+                Log.d(TAG, "更新后的 url_params_temp 值为:" + url + "?" + result)
+                webview.loadUrl(url+"?"+result)
+            } else {
+                Log.d(TAG, "load url:" + url)
+                webview.loadUrl(url)
+            }
+        } else {
+            showMessage("error: empty url!")
+        }
+//        webview.loadUrl("https://www.baidu.com/");
+        //带参数
+//        webview.loadDataWithBaseURL(HttpConstant.PATH, content, "text/html", "UTF-8", null);
+    }
+
+    override fun bindEvent() {
+        back_btn.setOnClickListener {
+            finish()
+//            push("/callingbed/main")
+        }
+    }
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        if (Constant.EVENT_FINISHh == messageEvent.type) {
+            finish()
+
+        }
+    }
+    override fun destory() {
+
+    }
+
+    override fun onError(message: String, type: Int) {
+
+    }
+
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    override fun start() {
+
+    }
+
+    override fun networkMonitor(state: NetState) {
+
+    }
+
+    override fun onBackPressed() {
+        if (webview.canGoBack()) {
+            webview.goBack()
+        } else {
+            this.finish()
+        }
+    }
+    private fun webviewSetting(webSettings: WebSettings) {
+        pb_web_base.setMax(100) //设置加载进度最大值
+        if (Build.VERSION.SDK_INT >= 19) {
+            webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //加载缓存否则网络
+        }
+        if (Build.VERSION.SDK_INT >= 19) {
+            webSettings.loadsImagesAutomatically = true //图片自动缩放 打开
+        } else {
+            webSettings.loadsImagesAutomatically = false //图片自动缩放 关闭
+        }
+
+        webview.setLayerType(View.LAYER_TYPE_NONE, null) //硬件解码
+        webSettings.javaScriptEnabled = true // 设置支持javascript脚本
+        webSettings.setSupportZoom(true) // 设置可以支持缩放
+        webSettings.builtInZoomControls = true // 设置出现缩放工具 是否使用WebView内置的缩放组件,由浮动在窗口上的缩放控制和手势缩放控制组成,默认false
+        webSettings.displayZoomControls = false //隐藏缩放工具
+        webSettings.useWideViewPort = false // 扩大比例的缩放
+        webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN //自适应屏幕
+        webSettings.loadWithOverviewMode = true
+        webSettings.databaseEnabled = false //
+        webSettings.savePassword = false //保存密码
+        webSettings.domStorageEnabled = true //是否开启本地DOM存储  鉴于它的安全特性(任何人都能读取到它,尽管有相应的限制,将敏感数据存储在这里依然不是明智之举),Android 默认是关闭该功能的。
+        webview.isSaveEnabled = true
+        webview.keepScreenOn = true
+        webSettings.textZoom = 100
+        // 设置setWebChromeClient对象
+        // 设置setWebChromeClient对象
+        webview.webChromeClient = object : WebChromeClient() {
+            override fun onReceivedTitle(view: WebView, title: String) {
+                super.onReceivedTitle(view, title)
+
+            }
+
+            override fun onProgressChanged(view: WebView, newProgress: Int) {
+                pb_web_base.setProgress(newProgress)
+                super.onProgressChanged(view, newProgress)
+            }
+        }
+        //设置此方法可在WebView中打开链接,反之用浏览器打开
+        webview.setWebViewClient(object : WebViewClient() {
+            override fun onPageFinished(view: WebView?, url: String?) {
+                super.onPageFinished(view, url)
+                if (!webview.getSettings().getLoadsImagesAutomatically()) {
+                    webview.getSettings().setLoadsImagesAutomatically(true);
+                }
+                pb_web_base.setVisibility(View.GONE);
+            }
+
+            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
+                pb_web_base.setVisibility(View.VISIBLE);
+                super.onPageStarted(view, url, favicon)
+            }
+
+            override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean {
+                // 在当前 WebView 中加载网页,而不是启动系统浏览器
+//                view.loadUrl(url!!)
+                return true
+            }
+
+        })
+    }
+}

+ 99 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/DeviceLinAdapter.kt

@@ -0,0 +1,99 @@
+package com.wdkl.app.ncs.callingbed.adapter
+
+import android.content.Context
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.model.vo.DeviceLinVo
+import com.wdkl.ncs.android.middleware.model.vo.DeviceMenulist
+
+class DeviceLinAdapter : RecyclerView.Adapter<DeviceLinAdapter.ViewHolder>{
+
+    private var context: Context
+    private var data: ArrayList<DeviceLinVo>
+    private lateinit var onItemClickListener: OnItemClickListener
+
+    constructor(context: Context, data: ArrayList<DeviceLinVo>): super() {
+        this.context = context
+        this.data = data
+    }
+
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        this.onItemClickListener = listener
+    }
+
+    fun updateData(data: ArrayList<DeviceLinVo>) {
+        this.data = data
+        notifyDataSetChanged()
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_icon_lay, parent, false)
+        val viewHolder = ViewHolder(view)
+
+        return viewHolder
+    }
+
+    override fun getItemCount(): Int {
+        return data.size
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        if ( data.get(position).name!=null){
+            holder.textView.text = data.get(position).name
+        }
+
+        if (data.get(position).device_type!=null ){
+            //分机
+            if (data.get(position).device_type==4){
+                holder.imageView.setImageResource(R.mipmap.dv_shebei)
+            }else if (data.get(position).device_type==21){
+                //紧急按钮
+                holder.imageView.setImageResource(R.mipmap.sos)
+            }else if (data.get(position).device_type==23){
+                //红外报警器
+                holder.imageView.setImageResource(R.mipmap.dv_hongwai)
+            }else if (data.get(position).device_type==30){
+                //烟雾报警器
+                holder.imageView.setImageResource(R.mipmap.dv_yanwu)
+            }else if (data.get(position).device_type==26){
+                //门磁
+                holder.imageView.setImageResource(R.mipmap.dv_menci)
+            }else if (data.get(position).device_type==43){
+                //睡眠床垫
+                holder.imageView.setImageResource(R.mipmap.dv_sleep_img)
+            }else{
+                holder.imageView.setImageResource(R.mipmap.dv_shebei)
+            }
+
+        }
+        holder.actionView.setOnClickListener {
+            onItemClickListener.onItemClick(holder.itemView, position)
+        }
+    }
+
+
+    class ViewHolder: RecyclerView.ViewHolder {
+        var actionView : View
+        var textView : TextView
+        var imageView : ImageView
+
+        constructor(itemView: View): super(itemView) {
+            actionView = itemView.findViewById(R.id.ll_menu_bt)
+            textView = itemView.findViewById(R.id.tx_menu)
+            imageView = itemView.findViewById(R.id.img_menu)
+        }
+    }
+
+    interface OnItemClickListener {
+        fun onItemClick(view: View, keyId: Int)
+    }
+}

+ 56 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/NumAdapter.java

@@ -0,0 +1,56 @@
+package com.wdkl.app.ncs.callingbed.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+public class NumAdapter extends BaseAdapter {
+    private String[] num;
+    private Context context;
+
+    public NumAdapter(String[] numbers, Context context) {
+        this.num = numbers;
+        this.context = context;
+    }
+
+
+    @Override
+    public int getCount() {
+        return num.length;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return num[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ViewHolder viewHolder;
+        if (convertView == null) {
+            convertView = LayoutInflater.from(context).inflate(R.layout.digital_item, null);
+            viewHolder = new ViewHolder();
+            viewHolder.numTv = convertView.findViewById(R.id.tv_number);
+            convertView.setTag(viewHolder);
+        } else {
+            viewHolder = (ViewHolder) convertView.getTag();
+        }
+        viewHolder.numTv.setText(num[position]);
+
+        return convertView;
+    }
+
+    static class ViewHolder {
+        TextView numTv;
+    }
+}

+ 77 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/adapter/NurseConfigAdpter.kt

@@ -0,0 +1,77 @@
+package com.wdkl.app.ncs.callingbed.adapter
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.ncs.android.middleware.model.dto.NurseConfigDto
+import com.wdkl.ncs.android.middleware.utils.StringUtil
+import java.lang.Exception
+
+class NurseConfigAdpter : RecyclerView.Adapter<NurseConfigAdpter.ViewHolder> {
+    private var context: Context
+    private var data: ArrayList<NurseConfigDto>
+
+    constructor(context: Context, data: ArrayList<NurseConfigDto>) {
+        this.context = context
+        this.data = data
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_nurse_config, parent, false)
+        val viewHolder = ViewHolder(view)
+
+        return viewHolder
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        try {
+            val drawableId: Int = context.resources.getIdentifier("shape_nurse_bg", "drawable", context.packageName)
+            val drawable: Drawable? = ContextCompat.getDrawable(context, drawableId)
+            val nurseColor: String? = data[position].nurseColorRbg
+            if (StringUtil.notEmpty(nurseColor)) {
+                val rgbValue = Color.parseColor("#" + data[position].nurseColorRbg)
+                drawable?.setTint(rgbValue)
+            } else {
+                drawable?.setTint(Color.parseColor("#e8e8e8"))
+            }
+            holder.bed_f_txt.background = drawable
+            holder.bed_f_txt.text = data[position].nurseOptionName
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+    }
+
+    override fun getItemCount(): Int {
+        return data.size
+    }
+
+    fun updateData(data: ArrayList<NurseConfigDto>) {
+        this.data = data
+        notifyDataSetChanged()
+    }
+
+    class ViewHolder: RecyclerView.ViewHolder {
+        //var nurseColor : TextView
+        var nurseName : TextView
+        var nurseValue : TextView
+        var nurseItem : LinearLayout
+        var bed_f_txt : TextView
+
+        constructor(itemView: View): super(itemView) {
+            //nurseColor = itemView.findViewById(R.id.tv_nurse_color)
+            bed_f_txt = itemView.findViewById(R.id.bed_f_txt)
+            nurseName = itemView.findViewById(R.id.tv_nurse_config_name)
+            nurseValue = itemView.findViewById(R.id.tv_nurse_config_value)
+            nurseItem = itemView.findViewById(R.id.ll_nurse_item)
+        }
+    }
+}

+ 12 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/agreement/CallingbedAgreement.kt

@@ -0,0 +1,12 @@
+package com.wdkl.app.ncs.callingbed.agreement
+
+import com.wdkl.ncs.android.middleware.model.dto.NurseConfigDto
+
+interface CallingbedAgreement {
+
+    //更新护理数据
+//    fun updateNurseConfig(list: List<NurseConfigDto>)
+
+    //检查APP版本
+    fun checkAppVersion()
+}

+ 30 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/broadcast/ScreenBroadcastReceiver.java

@@ -0,0 +1,30 @@
+package com.wdkl.app.ncs.callingbed.broadcast;
+
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import android.widget.TextView;
+
+
+public class ScreenBroadcastReceiver extends BroadcastReceiver {
+private String TAG = ScreenBroadcastReceiver.class.getSimpleName();
+
+    private TextView mBatteryView;
+
+//    public ScreenBroadcastReceiver(TextView mBatteryView) {
+//        this.mBatteryView = mBatteryView;
+//    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        Log.e(TAG,"收到亮屏广播"+action);
+//        if (intent.getAction().equals("com.wdkl.app.ncs.SCREEN")) {
+//         Log.e(TAG,"收到亮屏广播");
+////            EventBus.getDefault().post(new MessageEvent(power, Constants.Companion.getEVENT_WIFI_RSSI()));
+//        }
+    }
+}

+ 26 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/broadcast/WdBootReceiver.java

@@ -0,0 +1,26 @@
+package com.wdkl.app.ncs.callingbed.broadcast;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.util.Log;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+public class WdBootReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
+            if (!BuildConfig.flag.equals(Constant.DEV_Z_RK3128)) {
+                Log.d("wdBoot", "收到开机广播,启动app");
+                Intent startIntent = new Intent(context, WelcomeActivity.class);
+                startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(startIntent);
+            }
+        }
+    }
+}

+ 13 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BTConstants.java

@@ -0,0 +1,13 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+public class BTConstants {
+
+    //三诺的是这个固定值
+    public static final String ServiceUuid = "0000ffb0-0000-1000-8000-00805f9b34fb";
+    public static final String CharacteristicUuid = "0000ffb2-0000-1000-8000-00805f9b34fb";
+    //艾科
+    public static final String ServiceUuid2 = "11223344-5566-7788-99aa-bbccddeeff00";
+    public static final String CharacteristicUuid2 = "00004a5b-0000-1000-8000-00805f9b34fb";
+
+
+}

+ 368 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BaxcSocketConnect.java

@@ -0,0 +1,368 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+
+
+/**
+ * socket客户端 会粘包
+ * author 许柏胜
+ */
+public class BaxcSocketConnect implements SocketConnect {
+
+    private String ip;
+    private int port;
+    private String tag;
+    private byte[] heartbeat;
+    private long heartbeatTime = 5000;
+    private boolean isConnect;
+    private OnSocketReadListener onSocketReadListener;
+    private OnConnectStateListener onConnectStateListener;
+
+    private ConnectThread connectThread;
+    private InputStream inputStream;
+    private OutputStream outputStream;
+    private Socket socket;
+    private ReadThread readThread;
+    private HeartbeatThread heartbeatThread;
+
+    @Override
+    public int start() {
+        startConnectThread();
+        return 0;
+    }
+
+    @Override
+    public int release() {
+
+        stopConnectThread();
+        stopReadThread();
+        stopHeartbeatThread();
+
+        if (inputStream != null) {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            inputStream = null;
+        }
+
+        if (outputStream != null) {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            outputStream = null;
+        }
+
+        if (socket != null) {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            socket = null;
+        }
+
+        isConnect = false;
+
+        onConnectState(false);
+        return 0;
+    }
+
+    @Override
+    public int send(byte[] datas) {
+        return sendData(datas);
+    }
+
+    /**
+     * 连接线程
+     */
+    class ConnectThread extends Thread {
+        private boolean threadBool = false;
+        private int timeout = 5000;
+        private Socket socketTemp;
+        private boolean isConnected = false; //是否正在连接
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            isConnected = true;
+            while (threadBool) {
+                try {
+                    socketTemp = new Socket();
+                    socketTemp.connect(new InetSocketAddress(ip, port), timeout);
+                    isConnected = false;
+                    socket = socketTemp;
+                    inputStream = socket.getInputStream();
+                    outputStream = socket.getOutputStream();
+
+                    startReadThread();
+                    startHeartbeatThread();
+
+                    log("连接成功");
+                    isConnect = true;
+                    onConnectState(true);
+                    stopThread();
+                    break;
+                } catch (IOException e) {
+                    //e.printStackTrace();
+                    log("连接失败重新连接:" + ip + ":" + port);
+                }
+
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            log("退出连接线程" + ip + ":" + port);
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            if (isConnected) {
+                if (socketTemp != null) {
+                    try {
+                        socketTemp.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            interrupt();
+        }
+    }
+
+
+    private void log(String str) {
+        System.out.println(str);
+    }
+
+    private void startConnectThread() {
+        stopConnectThread();
+        connectThread = new ConnectThread();
+        connectThread.start();
+    }
+
+    private void stopConnectThread() {
+        if (connectThread != null) {
+            connectThread.stopThread();
+            connectThread = null;
+        }
+    }
+
+
+    void onConnectState(boolean connectState) {
+        if (onConnectStateListener != null) {
+            onConnectStateListener.onConnectState(this, connectState);
+        }
+    }
+
+    private void startHeartbeatThread() {
+        stopHeartbeatThread();
+        heartbeatThread = new HeartbeatThread();
+        heartbeatThread.start();
+    }
+
+    private void stopHeartbeatThread() {
+        if (heartbeatThread != null) {
+            heartbeatThread.stopThread();
+            heartbeatThread = null;
+        }
+    }
+
+    synchronized public int sendData(byte[] bytes) {
+        int ret = 0;
+        if (bytes == null || bytes.length == 0) return ret;
+        try {
+            if (outputStream != null) {
+                outputStream.write(bytes);
+                outputStream.flush();
+                ret = 0;
+            } else ret = -1;
+        } catch (SocketException e) {
+            //重启连接
+            release();
+            start();
+            sendData(bytes);
+        } catch (IOException e) {
+            e.printStackTrace();
+            ret = -2;
+        }
+        return ret;
+    }
+
+    /**
+     * 心跳线程
+     */
+    class HeartbeatThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            while (threadBool) {
+                int ret = sendData(getHeartbeat());
+                if (ret != 0) {
+                    stopThread();
+                    //重新连接
+                    log("发送失败,重新连接");
+                    release();
+                    startConnectThread();
+                    break;
+                }
+                try {
+                    Thread.sleep(heartbeatTime);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            log("退出心跳线程");
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+
+    private void startReadThread() {
+        stopReadThread();
+        readThread = new ReadThread();
+        readThread.start();
+    }
+
+    private void stopReadThread() {
+        if (readThread != null) {
+            readThread.stopThread();
+            readThread = null;
+        }
+    }
+
+
+    /**
+     * 读取数据线程
+     */
+    class ReadThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            while (threadBool) {
+                if (inputStream != null) {
+                    int size;
+                    try {
+                        byte[] buffer = new byte[64];
+
+                        size = inputStream.read(buffer);
+                        if (size > 0) {
+                            byte[] bytes = new byte[size];
+                            System.arraycopy(buffer, 0, bytes, 0, size);
+                            disposeReadData(bytes);
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        stopThread();
+                    }
+                }
+            }
+
+            log("退出读取数据线程");
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+    private void disposeReadData(byte[] bytes) {
+        onSocketRead(bytes);
+    }
+
+    private void onSocketRead(byte[] bytes) {
+        if (onSocketReadListener != null) {
+            onSocketReadListener.onSocketRead(this, bytes);
+        }
+    }
+
+    @Override
+    public boolean isConnect() {
+        return isConnect;
+    }
+
+    @Override
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    @Override
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    @Override
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    @Override
+    public void setHeartbeat(byte[] heartbeat) {
+        this.heartbeat = heartbeat;
+    }
+
+    @Override
+    public void setHeartbeatTime(long heartbeatTime) {
+        this.heartbeatTime = heartbeatTime;
+    }
+
+    @Override
+    public long getHeartbeatTime() {
+        return heartbeatTime;
+    }
+
+    @Override
+    public byte[] getHeartbeat() {
+        return heartbeat;
+    }
+
+    @Override
+    public String getIp() {
+        return ip;
+    }
+
+    @Override
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public String getTag() {
+        return tag;
+    }
+
+    @Override
+    public void setOnSocketReadListener(OnSocketReadListener onSocketReadListener) {
+        this.onSocketReadListener = onSocketReadListener;
+    }
+
+    @Override
+    public void setOnConnectStateListener(OnConnectStateListener onConnectStateListener) {
+        this.onConnectStateListener = onConnectStateListener;
+    }
+}

+ 369 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BaxcSocketConnectLine.java

@@ -0,0 +1,369 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * socket客户端 读取一行一行数据
+ * author 许柏胜
+ */
+public class BaxcSocketConnectLine implements SocketConnect {
+
+    private String ip;
+    private int port;
+    private String tag;
+    private byte[] heartbeat;
+    private long heartbeatTime = 5000;
+    private boolean isConnect;
+    private OnSocketReadListener onSocketReadListener;
+    private OnConnectStateListener onConnectStateListener;
+
+    private ConnectThread connectThread;
+    private BufferedReader bufferedReader;
+    private OutputStream outputStream;
+    private Socket socket;
+    private ReadThread readThread;
+    private HeartbeatThread heartbeatThread;
+
+    @Override
+    public int start() {
+        startConnectThread();
+        return 0;
+    }
+
+    @Override
+    public int release() {
+
+        stopConnectThread();
+        stopReadThread();
+        stopHeartbeatThread();
+
+        if (bufferedReader != null) {
+            try {
+                bufferedReader.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            bufferedReader = null;
+        }
+
+        if (outputStream != null) {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            outputStream = null;
+        }
+
+        if (socket != null) {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            socket = null;
+        }
+
+        isConnect = false;
+
+        onConnectState(false);
+        return 0;
+    }
+
+    @Override
+    public int send(byte[] datas) {
+        return sendData(datas);
+    }
+
+    /**
+     * 连接线程
+     */
+    class ConnectThread extends Thread {
+        private boolean threadBool = false;
+        private int timeout = 5000;
+        private Socket socketTemp;
+        private boolean isConnected = false; //是否正在连接
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            isConnected = true;
+            while (threadBool) {
+                try {
+                    socketTemp = new Socket();
+                    socketTemp.connect(new InetSocketAddress(ip, port), timeout);
+                    isConnected = false;
+                    socket = socketTemp;
+                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                    outputStream = socket.getOutputStream();
+
+                    startReadThread();
+                    startHeartbeatThread();
+
+                    log("连接成功");
+                    isConnect = true;
+                    onConnectState(true);
+                    stopThread();
+                    break;
+                } catch (IOException e) {
+                    //e.printStackTrace();
+                    log("连接失败重新连接:" + ip + ":" + port);
+                }
+
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            log("退出连接线程"+ip+":"+port);
+        }
+
+        public void stopThread() {
+            threadBool = false;
+
+            Log.e("xxxx","");
+
+            if (isConnected) {
+                if (socketTemp != null) {
+                    try {
+                        socketTemp.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            interrupt();
+        }
+    }
+
+
+    private void log(String str) {
+        System.out.println(str);
+    }
+
+    private void startConnectThread() {
+        stopConnectThread();
+        connectThread = new ConnectThread();
+        connectThread.start();
+    }
+
+    private void stopConnectThread() {
+        if (connectThread != null) {
+            connectThread.stopThread();
+            connectThread = null;
+        }
+    }
+
+
+
+    void onConnectState(boolean connectState) {
+        if (onConnectStateListener != null) {
+            onConnectStateListener.onConnectState(this, connectState);
+        }
+    }
+
+    private void startHeartbeatThread() {
+        stopHeartbeatThread();
+        heartbeatThread = new HeartbeatThread();
+        heartbeatThread.start();
+    }
+
+    private void stopHeartbeatThread() {
+        if (heartbeatThread != null) {
+            heartbeatThread.stopThread();
+            heartbeatThread = null;
+        }
+    }
+
+    synchronized public int sendData(byte[] bytes){
+        int ret = 0;
+        if(bytes == null || bytes.length == 0) return ret;
+        try {
+            if (outputStream != null) {
+                outputStream.write(bytes);
+                outputStream.flush();
+                ret = 0;
+            }else ret = -1;
+        } catch (IOException e) {
+            e.printStackTrace();
+            ret = -2;
+        }
+        return ret;
+    }
+
+    /**
+     * 心跳线程
+     */
+    class HeartbeatThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            while (threadBool) {
+                Log.e("sss777","心跳线程");
+                int ret = sendData(getHeartbeat());
+                if(ret != 0){
+                    stopThread();
+                    //重新连接
+                    log("发送失败,重新连接");
+                    release();
+                    startConnectThread();
+                    break;
+                }
+                try {
+                    Thread.sleep(heartbeatTime);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            log("退出心跳线程");
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+
+    private void startReadThread() {
+        stopReadThread();
+        readThread = new ReadThread();
+        readThread.start();
+    }
+
+    private void stopReadThread() {
+        if (readThread != null) {
+            readThread.stopThread();
+            readThread = null;
+        }
+    }
+
+
+    /**
+     * 读取数据线程
+     */
+    class ReadThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+            Log.e("sss","读取数据线程");
+            threadBool = true;
+            while (threadBool) {
+                Log.e("sss111","读取数据线程");
+                if (bufferedReader != null) {
+                    Log.e("sss222","读取数据线程");
+                    try {
+                        String str = bufferedReader.readLine();
+                        disposeReadData(str.getBytes());
+                        Log.e("sss333","读取数据线程");
+                    } catch (Exception e) {
+                        Log.e("sss44444","读取数据线程");
+                        e.printStackTrace();
+                        stopThread();
+                    }
+                }
+            }
+
+            log("退出读取数据线程");
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+    private void disposeReadData(byte[] bytes) {
+        onSocketRead(bytes);
+    }
+    private void onSocketRead(byte[] bytes){
+        Log.e("sss555","读取数据线程"+onSocketReadListener);
+        if(onSocketReadListener != null){
+            Log.e("sss666","读取数据线程");
+            onSocketReadListener.onSocketRead(this, bytes);
+        }
+    }
+
+    @Override
+    public boolean isConnect() {
+        return isConnect;
+    }
+
+    @Override
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    @Override
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    @Override
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    @Override
+    public void setHeartbeat(byte[] heartbeat) {
+        this.heartbeat = heartbeat;
+    }
+
+    @Override
+    public void setHeartbeatTime(long heartbeatTime) {
+        this.heartbeatTime = heartbeatTime;
+    }
+
+    @Override
+    public long getHeartbeatTime() {
+        return heartbeatTime;
+    }
+
+    @Override
+    public byte[] getHeartbeat() {
+        return heartbeat;
+    }
+
+    @Override
+    public String getIp() {
+        return ip;
+    }
+
+    @Override
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public String getTag() {
+        return tag;
+    }
+
+    @Override
+    public void setOnSocketReadListener(OnSocketReadListener onSocketReadListener) {
+        this.onSocketReadListener = onSocketReadListener;
+    }
+
+    @Override
+    public void setOnConnectStateListener(OnConnectStateListener onConnectStateListener) {
+        this.onConnectStateListener = onConnectStateListener;
+    }
+}

+ 506 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BluetoothService.java

@@ -0,0 +1,506 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig;
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.ncs.android.middleware.common.MessageEvent;
+
+import org.altbeacon.beacon.BeaconConsumer;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.RequiresApi;
+
+import static com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil.bytesToHex;
+
+public class BluetoothService extends Service implements BeaconConsumer, SocketConnect.OnConnectStateListener, SocketConnect.OnSocketReadListener {
+
+    private static String TAG = BluetoothService.class.getSimpleName();
+    private BluetoothAdapter bluetoothAdapter;
+
+    private static final int DATA_TYPE_FLAGS = 0x01;
+    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
+    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
+    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
+    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
+    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
+    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
+    private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
+    private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
+    private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
+    private static final int DATA_TYPE_SERVICE_DATA = 0x16;
+    private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
+
+    SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
+    private String localName = "";
+    private String ibeaconName = "";
+    private String address = "";
+    private String uuid = "";
+    private String majors = "";
+    private String minors = "";
+    private String rssis = "";
+    private String distances = "";
+    private int txPowerLevel = Integer.MIN_VALUE;
+    private String referenceData = "12FF10FF";//过滤我们的协议头
+    private String bloodPressureMeterDtat = "0000000000";//过滤血压仪数据
+    private String bloodGlucoseData = "F2";  //过滤血氧仪数据
+    private BaxcSocketConnectLine baxcSocketConnectLine;
+    private String ip = "47.115.176.250";
+    private int port = 3006;
+    private static BluetoothService bluetoothService;
+    public static boolean connectState = false;
+    private List<String> dataStringList = new ArrayList<>();
+    private long recordTime = 0;
+    private int SCREEN_TIME = 30;
+
+
+    public static final int NOTICE_ID = 100;
+    public static final String CHANNEL_ID_STRING = "nyd001";
+    public static String app_name = "APP";
+
+    private long time = 0;
+    NotificationUtil notificationUtil;
+
+    private BluetoothAdapter.LeScanCallback scanCallback;
+    private DataParse.OnDataCallback dataCallback;
+    private BluetoothStateBroadcastReceive mReceive;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new ServiceBinder();
+    }
+
+    public class ServiceBinder extends Binder {
+        public BluetoothService getService() {
+            return BluetoothService.this;
+        }
+
+        public void setData(String data) {
+            sendData(data);
+        }
+
+        public void setOnSignDataCallback(DataParse.OnDataCallback callback) {
+            dataCallback = callback;
+        }
+    }
+
+
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        EventBus.getDefault().register(this);
+
+        //启动通知栏
+        notificationUtil = new NotificationUtil(this);
+        //notificationUtil.ceShi();
+        startForeground(notificationUtil.notificationId, notificationUtil.getBuilder().build());
+        //启动蓝牙扫描
+        this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        scanCallback = new BluetoothAdapter.LeScanCallback() {
+            @Override
+            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
+                time = System.currentTimeMillis();
+
+                localName = "";
+                ibeaconName = "";
+                address = "";
+                uuid = "";
+                majors = "";
+                minors = "";
+                rssis = "";
+                distances = "";
+                txPowerLevel = Integer.MIN_VALUE;
+
+                //customParseData(device, rssi, scanRecord);//自定义解析数据 给蓝牙信标使用
+                parseData(device, rssi, scanRecord);//标准蓝牙协议解析数据
+
+            }
+        };
+
+        if (this.bluetoothAdapter.isEnabled()) {
+            if (SettingConfig.getBluetoothGatewayOn(this)) {
+                startScan();
+            }
+        } else {
+            //打开蓝牙
+            this.bluetoothAdapter.enable();
+            registerBluetoothReceiver();
+        }
+
+        //ip = "47.115.176.250";
+        //port = 3006;
+        ip = Constant.TCP_SERVER_URL;
+        port = Constant.TCP_VS_PORT;
+        Log.e(TAG, "ip " + ip + " port " + port);
+
+        bluetoothService = this;
+        baxcSocketConnectLine = new BaxcSocketConnectLine();
+        baxcSocketConnectLine.setIp(ip);
+        baxcSocketConnectLine.setPort(port);
+
+        baxcSocketConnectLine.setHeartbeatTime(1000 * 10);
+//        String data = String.format("0-%s:%s:%s",  NetFunctionConfig.getUser() + "", BaxcWebConfig.MACHINE_TYPE, Util.getDeviceId(WebSocketClinetService2.this)); //机构ID:机器类型:机器码
+        final String data = "12345678";
+        baxcSocketConnectLine.setHeartbeat(BluetoothUtil.hexStringToByteArray(data));//发送心跳数据
+        baxcSocketConnectLine.start();
+        baxcSocketConnectLine.setOnConnectStateListener(this);//监听是否在线
+        baxcSocketConnectLine.setOnSocketReadListener(this);  //监听返回数据
+
+    }
+
+    private void registerBluetoothReceiver(){
+        if(mReceive == null){
+            mReceive = new BluetoothStateBroadcastReceive();
+        }
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_OFF");
+        intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_ON");
+        registerReceiver(mReceive, intentFilter);
+    }
+
+    private void startScan() {
+        if (bluetoothAdapter != null) {
+            bluetoothAdapter.startLeScan(scanCallback);
+        }
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.e(TAG, "onStartCommand....");
+
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    /**
+     * 自定义解析数据 只给信标使用
+     *
+     * @param device
+     * @param rssi
+     * @param scanRecord
+     */
+    private void customParseData(BluetoothDevice device, int rssi, byte[] scanRecord) {
+        int startIndex = 2;
+        boolean patternFound = false;
+        Log.d(TAG, "handleScanResult: " + bytesToHex(scanRecord));
+        // 寻找是否存在beacon以及有效数据的起始索引
+        while (startIndex <= 5) {
+//            Log.e(TAG,"onLeScan 走了。。。"+startIndex);
+            if (((int) scanRecord[startIndex + 2] & 0xff) == 0x02
+                    && ((int) scanRecord[startIndex + 3] & 0xff) == 0x15) {
+                patternFound = true;
+//                Log.e(TAG,"onLeScan 走了222。。。");
+                break;
+            }
+            startIndex++;
+        }
+//        Log.e(TAG,"onLeScan 走了333。。。"+startIndex);
+
+        // 如果找到
+        if (patternFound) {
+            ibeaconName = device.getName();
+            address = device.getAddress();
+            Log.d(TAG, "customParseData(): 它的名字是" + ibeaconName);
+            Log.d(TAG, "customParseData(): 搜索到一个Beacon设备" + address);
+            parseBLEData(scanRecord, startIndex);
+            double distance = BluetoothUtil.rssi2distance(rssi);
+            distances = String.format("%.4f", distance);
+            Log.d(TAG, "customParseData(): RSSI=" + rssi + " distances " + distances);
+
+        } else {
+            String name = device.getName();
+            if (name == null) {
+                //Log.d(TAG, "onLeScan: 搜索到一个普通蓝牙设备,它的MAC是"+device.getAddress());
+            } else {
+                //Log.d(TAG, "onLeScan: 搜索到一个普通蓝牙设备,它的名字是"+name);
+            }
+        }
+
+    }
+
+    /**
+     * 标准蓝牙协议解析数据
+     *
+     * @param device
+     * @param rssi
+     * @param scanRecord
+     */
+    private void parseData(BluetoothDevice device, int rssi, byte[] scanRecord) {
+
+
+        if (recordTime == 0) {
+            recordTime = System.currentTimeMillis();
+        }
+        int currentPos = 0;
+        int advertiseFlag = -1;
+        if (scanRecord == null) {
+            return;
+        }
+        try {
+            while (currentPos < scanRecord.length) {
+                int length = scanRecord[currentPos++] & 0xFF;
+                if (length == 0) {
+                    break;
+                }
+                //Log.e(TAG, "蓝牙原始数据 " + bytesToHex(scanRecord));
+                int dataLength = length - 1;
+//                Log.e(TAG, "currentPos " + currentPos);
+//                Log.e(TAG, "length " + length);
+//                Log.e(TAG, "dataLength " + dataLength);
+                int fieldType = scanRecord[currentPos++] & 0xFF;
+//                Log.e(TAG, "fieldType " + fieldType + " DATA_TYPE_FLAGS " + DATA_TYPE_FLAGS);
+                switch (fieldType) {
+                    case DATA_TYPE_FLAGS:
+                        advertiseFlag = scanRecord[currentPos] & 0xFF;
+                        break;
+                    case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
+                    case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
+
+                        break;
+                    case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
+                    case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
+                        break;
+                    case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
+                    case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
+                        break;
+                    case DATA_TYPE_LOCAL_NAME_SHORT:
+                    case DATA_TYPE_LOCAL_NAME_COMPLETE:
+                        localName = new String(BluetoothUtil.extractBytes(scanRecord, currentPos, dataLength));
+                        break;
+                    case DATA_TYPE_TX_POWER_LEVEL:
+                        txPowerLevel = scanRecord[currentPos];
+                        break;
+                    case DATA_TYPE_SERVICE_DATA:
+                        break;
+                    case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
+                        // The first two bytes of the manufacturer specific data are
+                        // manufacturer ids in little endian.
+                        int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
+                                (scanRecord[currentPos] & 0xFF);
+                        final byte[] manufacturerDataBytes = BluetoothUtil.extractBytes(scanRecord, currentPos - 2,
+                                dataLength + 2);
+
+                        String data = bytesToHex(manufacturerDataBytes);
+                        String headData = data.substring(0, 8);
+                        if (referenceData.equals(headData)) {
+                            String serialNumber = data.substring(10, 20);//血压仪过滤
+                            String bloodGlucose = data.substring(8, 10);//血糖仪过滤
+                            Log.e(TAG, "发送的数据头部 " + headData);
+                            Log.e(TAG, "血压仪数据 " + serialNumber);
+                            Log.e(TAG, "血糖仪数据 " + bloodGlucose);
+                            if (!bloodPressureMeterDtat.equals(serialNumber)) {
+                                if (bloodGlucoseData.equals(bloodGlucose)) {
+                                    data = data.substring(0, data.length() - 2);
+                                }
+//                                Log.e(TAG,"时间 "+ (System.currentTimeMillis()-recordTime)/1000);
+                                if ((System.currentTimeMillis() - recordTime) / 1000 <= SCREEN_TIME) {
+
+                                    if (!dataStringList.contains(data)) {
+                                        dataStringList.add(data);
+                                        Log.e(TAG,"发送的数据 mac:"+device.getAddress());
+                                        Log.e(TAG, "发送的数据 " + data);
+                                        if (dataCallback != null) {
+                                            dataCallback.onData(data);
+                                        }
+//                                    sendData(data);
+//                                    String SS ="3418AA550000002B0000010000DB5755";
+                                        new Thread(new Runnable() {
+                                            @Override
+                                            public void run() {
+                                                if (baxcSocketConnectLine != null) {
+                                                    baxcSocketConnectLine.send(manufacturerDataBytes);
+                                                }
+                                            }
+                                        }).start();
+
+                                    }
+                                } else {
+                                    Log.e(TAG, "时间到了。。。 ");
+                                    dataStringList.clear();
+                                    recordTime = 0;
+                                }
+                            }
+                        }
+
+                        break;
+                    default:
+                        // Just ignore, we don't handle such data type.
+                        break;
+                }
+                currentPos += dataLength;
+//                Log.e(TAG, "------ " + currentPos);
+            }
+
+        } catch (Exception e) {
+            Log.e(TAG, "解析蓝牙数据异常 " + e.getMessage());
+        }
+
+    }
+
+    // 解析BLE数据
+    public void parseBLEData(byte[] scanRecord, int startIndex) {
+        // uuid的长度是16bytes
+        byte[] uuidBytes = new byte[16];
+        System.arraycopy(scanRecord, startIndex + 4, uuidBytes, 0, 16);
+        String hexString = bytesToHex(uuidBytes);
+        // beacon的UUID值
+        uuid = BluetoothUtil.parseUUID(hexString);
+        // beacon的Major值
+        int major = (scanRecord[startIndex + 20] & 0xff) * 0x100
+                + (scanRecord[startIndex + 21] & 0xff);
+        majors = major + "";
+        // ibeacon的Minor值
+        int minor = (scanRecord[startIndex + 22] & 0xff) * 0x100
+                + (scanRecord[startIndex + 23] & 0xff);
+        minors = minor + "";
+        txPowerLevel = (scanRecord[startIndex + 24]);
+        Log.d(TAG, "parseBLEData() 它的UUID是" + uuid + ",txPower是" + txPowerLevel);
+        Log.d(TAG, "parseBLEData() major=" + major + ",minor=" + minor);
+    }
+
+    @Override
+    public void onBeaconServiceConnect() {
+
+    }
+
+    /**
+     * @param install
+     * @param connectState true为连接成功 false为断开连接
+     */
+    @Override
+    public void onConnectState(SocketConnect install, boolean connectState) {
+        this.connectState = connectState;
+        Log.e(TAG, "连接服务器是否成功 " + connectState);
+    }
+
+    /**
+     * 服务是否存活
+     *
+     * @return true: 存活
+     */
+    public static boolean isServiceRunning() {
+        return bluetoothService != null;
+    }
+
+    @Override
+    public void onSocketRead(SocketConnect install, byte[] bytes) {
+
+        /*String data = bytesToHex(bytes);
+        Log.e(TAG, "返回的数据data " + data);
+        Log.e(TAG, "返回的数据 dd " + (System.currentTimeMillis() - time) / 1000);
+        if (time == 0) return;
+        if ((System.currentTimeMillis() - time) / 1000 >= 2) {
+            time = 0;
+            baxcSocketConnectLine.release();
+            notificationUtil.setProgres(notificationUtil.progressMax + 5);
+
+            EventBus.getDefault().post(new MessageEvent("bt", Constant.EVENT_RESTART_BT));
+        }*/
+
+    }
+
+    /**
+     * 发送数据
+     *
+     * @param data
+     */
+    public void sendData(final String data) {
+        if (baxcSocketConnectLine != null) {
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    Log.e(TAG, "发送的数据 " + data);
+                    baxcSocketConnectLine.send(BluetoothUtil.hexStringToByteArray(data));
+                }
+            }).start();
+
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.e(TAG, "蓝牙服务关闭");
+        EventBus.getDefault().unregister(this);
+
+        /*if (bluetoothAdapter != null) {
+            bluetoothAdapter.stopLeScan(scanCallback);
+        }
+        if (baxcSocketConnectLine != null) {
+            baxcSocketConnectLine.release();
+        }*/
+
+        bluetoothService = null;
+
+        if(mReceive != null){
+            unregisterReceiver(mReceive);
+            mReceive = null;
+        }
+    }
+
+
+    private class BluetoothStateBroadcastReceive extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            switch (action){
+                case BluetoothDevice.ACTION_ACL_CONNECTED:
+                case BluetoothDevice.ACTION_ACL_DISCONNECTED:
+                    break;
+                case BluetoothAdapter.ACTION_STATE_CHANGED:
+                    int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
+                    if (blueState == BluetoothAdapter.STATE_OFF) {
+                        Log.e(TAG, "蓝牙已关闭");
+                    } else if (blueState == BluetoothAdapter.STATE_ON) {
+                        Log.d(TAG, "蓝牙已打开");
+                        startScan();
+                    }
+                    break;
+            }
+        }
+    }
+
+
+    @Subscribe(threadMode = ThreadMode.ASYNC)
+    public void onMoonEvent(MessageEvent messageEvent) {
+        switch (messageEvent.getType()) {
+            case Constant.EVENT_BLE_START:
+                startScan();
+                if (baxcSocketConnectLine != null) {
+                    baxcSocketConnectLine.start();
+                }
+                break;
+
+            case Constant.EVENT_BLE_STOP:
+                if (bluetoothAdapter != null) {
+                    bluetoothAdapter.stopLeScan(scanCallback);
+                }
+                if (baxcSocketConnectLine != null) {
+                    baxcSocketConnectLine.release();
+                }
+                break;
+        }
+    }
+}

+ 156 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/BluetoothUtil.java

@@ -0,0 +1,156 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+public class BluetoothUtil {
+
+
+    /**
+     * Hex转byte[],两种情况,Hex长度为奇数最后一个字符会被舍去
+     */
+    public static byte[] hexTobytes(String hex) {
+        if (hex.length() < 1) {
+            return null;
+        } else {
+            byte[] result = new byte[hex.length() / 2];
+            int j = 0;
+            for(int i = 0; i < hex.length(); i+=2) {
+                result[j++] = (byte) Integer.parseInt(hex.substring(i,i+2), 16);
+            }
+            return result;
+        }
+    }
+
+    // Helper method to extract bytes from byte array.
+    public static byte[] extractBytes(byte[] scanRecord, int start, int length) {
+        byte[] bytes = new byte[length];
+        System.arraycopy(scanRecord, start, bytes, 0, length);
+        return bytes;
+    }
+
+    // 格式化UUID
+    public static String parseUUID(String data) {
+        String uuid = "";
+        if (data.length() == 32) {
+            uuid = data.substring(0, 8) + "-"
+                    + data.substring(8, 12) + "-"
+                    + data.substring(12, 16) + "-"
+                    + data.substring(16, 20) + "-"
+                    + data.substring(20);
+        } else {
+//            showTips(getString(R.string.toast_uuid_not_found));
+        }
+        return uuid;
+    }
+
+    /**
+     * byte数组转化为string
+     */
+    static final char[] hexArray = "0123456789ABCDEF".toCharArray();
+    public static String bytesToHex(byte[] bytes) {
+        char[] hexChars = new char[bytes.length * 2];
+        for (int j = 0; j < bytes.length; j++) {
+            int v = bytes[j] & 0xFF;
+            hexChars[j * 2] = hexArray[v >>> 4];
+            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+        }
+        return new String(hexChars);
+    }
+
+    // 根据RSSI计算距离
+    public static double rssi2distance(int rssi) {
+        int iRssi = Math.abs(rssi);
+        // 发射端和接收端相隔1米时的信号强度
+        int A = 59;
+        // 环境噪声衰减因子
+        double n = 2.0;
+        double power = (iRssi - A) / (10 * n);
+        return Math.pow(10, power);
+    }
+
+    public static byte[] hexStringToByteArray(String hexString) {
+        hexString = hexString.replaceAll(" ", "");
+        int len = hexString.length();
+        byte[] bytes = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            // 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
+            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
+                    .digit(hexString.charAt(i + 1), 16));
+        }
+        return bytes;
+    }
+
+    /**
+     * 16进制转换成为string类型字符串
+     * @param s
+     * @return
+     */
+    public static String hexStringToString(String s) {
+        if (s == null || s.equals("")) {
+            return null;
+        }
+        s = s.replace(" ", "");
+        byte[] baKeyword = new byte[s.length() / 2];
+        for (int i = 0; i < baKeyword.length; i++) {
+            try {
+                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        try {
+            s = new String(baKeyword, "UTF-8");
+            new String();
+        } catch (Exception e1) {
+            e1.printStackTrace();
+        }
+        return s;
+    }
+
+    /**
+     * 字符串转化成为16进制字符串
+     * @param s
+     * @return
+     */
+    public static String strTo16(String s) {
+        String str = "";
+        for (int i = 0; i < s.length(); i++) {
+            int ch = (int) s.charAt(i);
+            String s4 = Integer.toHexString(ch);
+            str = str + s4;
+        }
+        return str.toUpperCase();
+    }
+
+    public static String intToTwoBytesHexString(int number) {
+        // 将整数转换为两个字节的十六进制表示
+        byte[] bytes = new byte[2];
+        bytes[0] = (byte) ((number >> 8) & 0xFF);  // 高位字节
+        bytes[1] = (byte) (number & 0xFF);         // 低位字节
+
+        // 将字节数组转换为十六进制字符串
+        StringBuilder hexString = new StringBuilder();
+        for (byte b : bytes) {
+            hexString.append(String.format("%02X", b));
+        }
+        return hexString.toString();
+    }
+
+    /**
+     * 10进制转化成为16进制字符串
+     * @return
+     */
+    public static String hex10To16(String valueTen) {
+        return String.format("%04X",valueTen);//自定义保留几位
+    }
+    /**
+     * 16进制字符串转化成为10进制
+     * @return
+     */
+    public static int hexToDecimal(String hexString) {
+        try {
+            return Integer.parseInt(hexString, 16);
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+}

+ 133 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/DataParse.java

@@ -0,0 +1,133 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+import android.util.Log;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+public class DataParse {
+    private final static String TAG = "SignDataParse";
+
+    //体征数据解析
+    public static SignData parseValue(String result) {
+        //体温: 12FF10FFF13E9DD6673178870E150000000000
+        result = result.replaceAll(" ", "").toLowerCase();
+        Log.d(TAG, "original sign data: " + result);
+        if (!result.substring(0, 8).equalsIgnoreCase("12ff10ff")) {
+            return null;
+        }
+        String lx = result.substring(8, 10);
+        String mac = getMac(lx, result);
+        Log.d(TAG, "lx: " + lx + ", mac: " + mac);
+        SignData signData = new SignData();
+
+        switch (lx) {
+            case "ff": // 这是血压的数据
+                long highPressure = Long.parseLong(result.substring(12, 14), 16);
+                long lowPressure = Long.parseLong(result.substring(14, 16), 16);
+                long pulse = Long.parseLong(result.substring(16, 18), 16);
+                if (highPressure != 0) {
+                    signData.highPressure = highPressure;
+                }
+                if (lowPressure != 0) {
+                    signData.lowPressure = lowPressure;
+                }
+                if (pulse != 0) {
+                    signData.pulse = pulse;
+                }
+                signData.type = 4;
+                Log.d(TAG, "高压:" + highPressure + ";低压:" + lowPressure + ";脉搏:" + pulse);
+                break;
+            case "f1": // 这是体温的数据
+                String animalHeat = Long.parseLong(result.substring(24, 28), 16) + "";
+                if (animalHeat.length() < 3) {
+                    return null;
+                }
+                if (animalHeat.length() == 3) {
+                    animalHeat += "0";
+                }
+                BigDecimal decimal = new BigDecimal(animalHeat.substring(0, 2) + "." + animalHeat.substring(2, 4));
+                double animalHeatVue = decimal.divide(BigDecimal.ONE, 1, RoundingMode.HALF_UP).doubleValue();
+                if (animalHeatVue != 0) {
+                    signData.temperature = animalHeatVue;
+                }
+                signData.type = 1;
+                Log.d(TAG, "体温为:" + animalHeatVue);
+                break;
+            case "f2": // 这是血氧的数据
+                long heartStartValue = Long.parseLong(result.substring(26, 28), 16);
+                long heartEndValue = Long.parseLong(result.substring(28, 30), 16);
+                long heartValue = heartStartValue + heartEndValue;
+                if (heartValue != 0) {
+                    signData.heartValue = heartValue;
+                }
+                long bloodValue = Long.parseLong(result.substring(30, 32), 16);
+                if (bloodValue != 0 && bloodValue != 1) {
+                    signData.bloodValue = bloodValue;
+                }
+                signData.type = 2;
+                Log.d(TAG, "血氧为:" + bloodValue + ";心率为:" + heartValue);
+                break;
+            case "f3": // 这是血糖的数据
+                String valStr = Long.parseLong(result.substring(16, 20), 16) + "";
+                if (valStr.length() > 4) {
+                    return null;
+                }
+                int dw = Integer.parseInt(result.substring(21, 22));
+                double value = Double.parseDouble(valStr.substring(0, (valStr.length() - dw)) + "." + valStr.substring(valStr.length() - dw));
+                if (value != 0) {
+                    signData.bloodGlucose = value;
+                }
+                signData.type = 3;
+                Log.d(TAG, "血糖为" + value);
+                break;
+        }
+
+        return signData;
+    }
+
+    // 获取设备Mac地址
+    public static String getMac(String lx, String result) {
+        String macStr = null; // 体征设备Mac地址
+        switch (lx) {
+            case "ff":
+                if (result.substring(10, 13).equalsIgnoreCase("000")) { // 血压计发送的垃圾信息需过滤
+                    macStr = null;
+                } else {
+                    macStr = result.substring(20, 32);
+                }
+                break;
+            case "f1":
+                if (result.startsWith("0000", 24)) { // 体温枪发送的垃圾信息需过滤
+                    macStr = null;
+                } else {
+                    macStr = result.substring(12, 24);
+                }
+                break;
+            case "f2":
+                if (result.startsWith("0000", 26)) { // 血氧仪发送的垃圾信息需过滤
+                    macStr = null;
+                } else {
+                    macStr = result.substring(14, 26);
+                }
+                break;
+            case "f3":
+                macStr = result.substring(26, 38);
+                break;
+        }
+        if (macStr == null) {
+            return null;
+        }
+        StringBuilder builder = new StringBuilder();
+        int length = macStr.length() / 2;
+        // 根据mac地址字符串生成mac地址
+        for (int i = 0; i < length; i++) {
+            builder.append(macStr, i * 2, i * 2 + 2).append(":");
+        }
+        return builder.deleteCharAt(builder.length() - 1).toString();
+    }
+
+    public interface OnDataCallback {
+        void onData(String data);
+    }
+}

+ 38 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/Device.java

@@ -0,0 +1,38 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+
+import com.clj.fastble.data.BleDevice;
+
+import java.io.Serializable;
+
+public class Device implements Serializable {
+    private BleDevice device;
+    private BluetoothGattCharacteristic characteristic;
+    private int writeType = -1;
+
+
+    public BleDevice getDevice() {
+        return device;
+    }
+
+    public void setDevice(BleDevice device) {
+        this.device = device;
+    }
+
+    public BluetoothGattCharacteristic getCharacteristic() {
+        return characteristic;
+    }
+
+    public void setCharacteristic(BluetoothGattCharacteristic characteristic) {
+        this.characteristic = characteristic;
+    }
+
+    public int getWriteType() {
+        return writeType;
+    }
+
+    public void setWriteType(int writeType) {
+        this.writeType = writeType;
+    }
+}

+ 143 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/NotificationUtil.java

@@ -0,0 +1,143 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Build;
+
+import com.enation.javashop.android.welcome.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import androidx.annotation.RequiresApi;
+
+import static android.content.Context.NOTIFICATION_SERVICE;
+
+/**
+ * 通知栏工具
+ */
+public class NotificationUtil {
+
+    private String TAG = NotificationUtil.class.getSimpleName();
+    private Context mContext;
+    private NotificationManager notificationManager;
+    private int progress = 0;
+    public int progressMax = 600;
+    public int notificationId = 0x2154;
+    private Notification.Builder builder;
+    private String ContentTitle = "care service";
+    private String ContentText = "running...";
+    String channelId = "my_channel_01";
+    String name = "my_channel";
+
+    private SimpleDateFormat sdfInput = new SimpleDateFormat("mm:ss ");
+
+    /**
+     * @param context
+     */
+    public NotificationUtil(Context context) {
+        this.mContext = context;
+        notificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
+        sendNotification();
+    }
+
+    public Notification.Builder getBuilder(){
+        return builder;
+    }
+
+    public void setProgres(int progress){
+        this.progress = progress;
+    }
+
+    @TargetApi(Build.VERSION_CODES.O)
+    private void sendNotification() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            @SuppressLint("WrongConstant")
+            NotificationChannel mChannel = new NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_LOW);
+            notificationManager.createNotificationChannel(mChannel);
+            builder = new Notification.Builder(mContext)
+                    .setChannelId(channelId)  //设置渠道id
+                    .setContentTitle(ContentTitle)
+                    .setContentText(ContentText)
+                    .setSmallIcon(R.mipmap.launcher);
+
+
+            //创建点击跳转Intent 不会重新新建界面
+            /*Intent intent = new Intent(mContext, MainActivity.class);
+            //创建任务栈Builder
+            TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
+            stackBuilder.addParentStack(MainActivity.class);
+            stackBuilder.addNextIntent(intent);
+            PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
+            builder.setContentIntent(pendingIntent);*/
+        } else {
+            builder = new Notification.Builder(mContext)
+                    .setContentTitle(ContentTitle)
+                    .setContentText(ContentText)
+                    .setSmallIcon(R.mipmap.launcher)
+                    .setOngoing(true);
+//                    .setChannelId(channelId);//无效
+        }
+        notificationManager.notify(notificationId, builder.build());
+    }
+
+
+    /**
+     * @param contentText
+     * @return
+     */
+    public NotificationUtil setContentText(String contentText) {
+        ContentText = contentText;
+        return NotificationUtil.this;
+    }
+
+
+    /**
+     * @param contentTitle
+     * @return
+     */
+    public NotificationUtil setContentTitle(String contentTitle) {
+        ContentTitle = contentTitle;
+        return NotificationUtil.this;
+    }
+
+
+    /**
+     * @param progress
+     */
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+    public void setProgress(int progress) {
+        if (builder == null) return;
+        builder.setProgress(progressMax, progress, false);
+        builder.setContentTitle(sdfInput.format(new Date(progress*1000)));
+        if (progress == progressMax) {
+            builder.setContentTitle("download complete");
+            //自动移除
+            notificationManager.cancel(notificationId);
+        } else {
+            notificationManager.notify(notificationId, builder.build());//显示通知
+        }
+    }
+
+
+    public void ceShi() {
+        new Thread(new Runnable() {
+            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+            @Override
+            public void run() {
+                while (progress++ < progressMax) {
+                    setProgress(progress);
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }).start();
+    }
+}

+ 20 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/SignData.java

@@ -0,0 +1,20 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+public class SignData {
+    public int type; //1-体温,2-血氧,3-血糖,4-血压
+
+    //血压数据
+    public long highPressure; //收缩压
+    public long lowPressure; //舒张压
+    public long pulse; //脉搏
+
+    //体温数据
+    public double temperature;
+
+    //血氧数据
+    public long bloodValue; //血氧
+    public long heartValue; //心率
+
+    //血糖数据
+    public double bloodGlucose;
+}

+ 80 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/bt_gateway/SocketConnect.java

@@ -0,0 +1,80 @@
+package com.wdkl.app.ncs.callingbed.bt_gateway;
+
+
+/**
+ * socket连接类 断开连接可自动重连
+ * author 许柏胜
+ */
+public interface SocketConnect {
+    int ERROR_START_FAIL = -1;
+    int ERROR_RELEASE_FAIL = -1;
+    int ERROR_SEND_NOT_CONNECT = -1; //未连接
+    int ERROR_SEND_IO_ERROR = -2; //IO异常
+
+    /**
+     * 开始连接
+     * @return 0为成功 非0为失败
+     */
+    int start();
+
+    /**
+     * 释放资源
+     * @return 0为成功 非0为失败
+     */
+    int release();
+
+    /**
+     * 发送数据
+     * @param datas
+     * @return 小于0为失败
+     */
+    int send(byte[] datas);
+
+    boolean isConnect();
+
+    void setIp(String ip);
+    void setPort(int port);
+    void setTag(String tag);
+
+    /**
+     * 设置心跳
+     * @param heartbeat
+     */
+    void setHeartbeat(byte[] heartbeat);
+
+    /**
+     * 设置心跳间隔时间
+     * @param heartbeatTime 默认为5秒
+     */
+    void setHeartbeatTime(long heartbeatTime);
+
+    long getHeartbeatTime();
+    byte[] getHeartbeat();
+    String getIp();
+    int getPort();
+    String getTag();
+
+
+    void setOnSocketReadListener(OnSocketReadListener onSocketReadListener);
+
+    void setOnConnectStateListener(OnConnectStateListener onConnectStateListener);
+
+    /**
+     * 读取回调
+     */
+    interface OnSocketReadListener{
+        void onSocketRead(SocketConnect install, byte[] bytes);
+    }
+
+    /**
+     * 连接状态监听
+     */
+    interface OnConnectStateListener{
+        /**
+         *
+         * @param connectState true为连接成功 false为断开连接
+         */
+        void onConnectState(SocketConnect install, boolean connectState);
+    }
+
+}

+ 39 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/di/CallingbedComponent.kt

@@ -0,0 +1,39 @@
+package com.wdkl.app.ncs.callingbed.di
+
+import com.wdkl.app.ncs.callingbed.activity.*
+import com.wdkl.app.ncs.callingbed.fragment.*
+
+import com.wdkl.ncs.android.middleware.di.ApplicationComponent
+import dagger.Component
+
+@Component(dependencies = arrayOf(ApplicationComponent::class))
+interface CallingbedComponent {
+    fun inject(activity: CallingbedActivity)
+
+    fun inject(activity: AppUpdateActivity)
+
+    fun inject(activity: CallingbedActivationActivity)
+
+    fun inject(activity: SystemActivity)
+
+    fun inject(activity: WebviewActivity)
+
+    fun inject(activity: SleepMonitoringActivity)
+
+    fun inject(activity: DeviceSystemActivity)
+
+    fun inject(activity: DeviceLinkageActivity)
+
+
+    fun inject(fragment: MainFragment)
+
+    fun inject(fragment: apartmentFragment)
+
+    fun inject(fragment: SleepGraphOfCurveFragment)
+
+    fun inject(fragment: SleepDataTableFragment)
+
+
+
+
+}

+ 112 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/CallConfigDialogHelper.java

@@ -0,0 +1,112 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.zhyl.ZhylManager;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+
+public class CallConfigDialogHelper {
+
+    private static AlertDialog alertDialog;
+    private static String network="";
+
+    public static void showDialog(Activity activity) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.call_config_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        LinearLayout layout = contentView.findViewById(R.id.ll_net_config_view);
+        EditText call_config_mic = contentView.findViewById(R.id.call_config_mic);
+        EditText call_config_horn = contentView.findViewById(R.id.call_config_horn);
+        Button call_config_cancel_button = contentView.findViewById(R.id.call_config_cancel_button);
+        Button call_config_determine_button = contentView.findViewById(R.id.call_config_determine_button);
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(alertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+
+
+        try {
+
+            int mic1 = ZhylManager.getInstance(BaseApplication.appContext).sys_getMic1gain(BaseApplication.appContext);
+            int yl2 = ZhylManager.getInstance(BaseApplication.appContext).sys_getDacVolume(BaseApplication.appContext);
+//
+            call_config_mic.setText(String.valueOf(mic1));
+            call_config_horn.setText(String.valueOf(yl2));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        call_config_cancel_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+
+            }
+        });
+        call_config_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                int mic = Integer.parseInt(call_config_mic.getText().toString());
+                int yl =  Integer.parseInt(call_config_horn.getText().toString());
+                    alertDialog.dismiss();
+                    try {
+                        //设置静态网络
+                        if (ZhylManager.getInstance(BaseApplication.appContext).sys_setDacVolume(BaseApplication.appContext,yl) == 1 &&
+                                ZhylManager.getInstance(BaseApplication.appContext).sys_setMic1gain(BaseApplication.appContext,mic) == 1) {
+                            showMessage("Success");
+                            SettingConfig.setMIC(activity, mic);
+                            SettingConfig.setHORN(activity, yl);
+                        } else {
+                            showMessage("Failed");
+                        }
+                    } catch (Exception e) {
+                        showMessage("Failed");
+                    }
+                }
+
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 450;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 115 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/DeviceLinkDialogHelper.java

@@ -0,0 +1,115 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.helper.NetHelper;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+import com.wdkl.ncs.android.lib.utils.NetParam;
+import com.wdkl.ncs.android.middleware.model.vo.DeviceLinVo;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+
+
+
+public class DeviceLinkDialogHelper {
+
+    private static AlertDialog alertDialog;
+    private static String network="";
+
+
+    public static void showDialog(Activity activity , DeviceLinVo str, ClickListener clickListener) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_dev_lin_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        LinearLayout layout = contentView.findViewById(R.id.dev_lin_ll_net_config_view);
+        TextView hili_top_text = contentView.findViewById(R.id.dev_lin_name);
+        EditText network2_ip = contentView.findViewById(R.id.dev_lin_ip);
+        EditText network2_wg = contentView.findViewById(R.id.dev_lin_wg);
+        EditText network2_ym = contentView.findViewById(R.id.dev_lin_ym);
+        EditText network2_dns = contentView.findViewById(R.id.dev_lin_dns);
+        Button network2_cancel_button = contentView.findViewById(R.id.dev_lin__cancel_button);
+        Button network2_determine_button = contentView.findViewById(R.id.dev_lin__determine_button);
+        hili_top_text.setText(str.getName());
+
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(alertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+        if (str.getDevice_type()==43){
+            //如果是床垫
+            network2_cancel_button.setVisibility(View.VISIBLE);
+        }else {
+            network2_cancel_button.setVisibility(View.GONE);
+        }
+
+        network2_ip.setText(str.getEth_mac());
+        network2_wg.setText(str.getCode());
+        network2_ym.setText(str.getModel());
+        network2_dns.setText(str.getHard_ver());
+
+
+
+        network2_cancel_button.setOnClickListener(v -> {
+            clickListener.onClick(str.getEth_mac());
+        });
+        network2_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    public interface ClickListener{
+        void onClick(String bedVO);
+    }
+    public static void dismissCallDialog() {
+        if (alertDialog != null) {
+            alertDialog.dismiss();
+        }
+    }
+}

+ 98 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/DeviceLinkSleepDialogHelper.java

@@ -0,0 +1,98 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.ncs.android.middleware.model.vo.DeviceLinVo;
+
+/**
+ * 通知密码
+ * */
+public class DeviceLinkSleepDialogHelper {
+
+    private static AlertDialog linkalertDialog;
+    private static String network="";
+
+
+    public static void showDialog(Activity activity , ClickListener clickListener) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_dev_lin_wifi_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        LinearLayout layout = contentView.findViewById(R.id.dev_lin_wifi_ll_net_config_view);
+        EditText network2_ip = contentView.findViewById(R.id.dev_lin_wifi_ip);
+        EditText network2_wg = contentView.findViewById(R.id.dev_lin_wifi_wg);
+        Button bt_sleep_link_cancel_button = contentView.findViewById(R.id.dev_lin_wifi_cancel_button);
+        Button bt_sleep_link_determine_button = contentView.findViewById(R.id.dev_lin_wifi_determine_button);
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(linkalertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+
+        bt_sleep_link_cancel_button.setOnClickListener(v -> {
+
+        });
+        bt_sleep_link_determine_button.setOnClickListener(v -> {
+            if (linkalertDialog != null && linkalertDialog.isShowing()) {
+                linkalertDialog.dismiss();
+                String name = network2_ip.getText().toString();
+                String Password = network2_wg.getText().toString();
+                if (!name.equals("")&& !Password.equals("")){
+                    clickListener.onClick(name,Password);
+                }
+
+            }
+
+        });
+        linkalertDialog = builder.create();
+        linkalertDialog.setCanceledOnTouchOutside(true);
+        linkalertDialog.setCancelable(true);
+        linkalertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = linkalertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    public interface ClickListener{
+        void onClick(String name,String Password);
+    }
+    public static void dismissCallDialog() {
+        if (linkalertDialog != null && linkalertDialog.isShowing()) {
+            linkalertDialog.dismiss();
+        }
+    }
+}

+ 113 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/Network2DialogHelper.java

@@ -0,0 +1,113 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.helper.NetHelper;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+import com.wdkl.ncs.android.lib.utils.NetParam;
+//import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+
+public class Network2DialogHelper {
+
+    private static AlertDialog alertDialog;
+    private static String network="";
+
+    public static void showDialog(Activity activity) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_network_two_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        LinearLayout layout = contentView.findViewById(R.id.ll_net_config_view);
+        EditText network2_ip = contentView.findViewById(R.id.network2_ip);
+        EditText network2_wg = contentView.findViewById(R.id.network2_wg);
+        EditText network2_ym = contentView.findViewById(R.id.network2_ym);
+        EditText network2_dns = contentView.findViewById(R.id.network2_dns);
+        Button network2_cancel_button = contentView.findViewById(R.id.network2_cancel_button);
+        Button network2_determine_button = contentView.findViewById(R.id.network2_determine_button);
+
+        TextView server_determine_button = contentView.findViewById(R.id.server_determine_button);
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(alertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+
+        network2_ip.setText(NetHelper.getInstance().getLocalIP());
+        NetParam netParam = NetHelper.getNetInfo(activity);
+        if (netParam != null) {
+            network2_wg.setText(netParam.getGateway());
+            network2_ym.setText(netParam.getNetMask());
+            network2_dns.setText(netParam.getDns1());
+        }
+
+        network2_cancel_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+
+            }
+        });
+        network2_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                String IP = network2_ip.getText().toString();
+                String ym = network2_ym.getText().toString();
+                String wg = network2_wg.getText().toString();
+                String dns = network2_dns.getText().toString();
+                if (IP.isEmpty()&&ym.isEmpty()&&wg.isEmpty()&&dns.isEmpty()){
+                    showMessage(R.string.param_set_error);
+                }
+                alertDialog.dismiss();
+
+                //设置静态网络
+                if (EthernetUtils.setEthernetStaticIp(activity,IP,ym,wg,dns)) {
+                    showMessage("Success");
+                } else {
+                    showMessage("Failed");
+                }
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+}

+ 105 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/NetworkDialogHelper.java

@@ -0,0 +1,105 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+//import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+public class NetworkDialogHelper {
+
+    private static AlertDialog alertDialog;
+    private static String network="";
+
+    public static void showDialog(Activity activity) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_network_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        TextView network_one_tx = contentView.findViewById(R.id.network_one_tx);
+        TextView network_two_tx = contentView.findViewById(R.id.network_two_tx);
+        Button network_button = contentView.findViewById(R.id.network_button);
+
+        int type = EthernetUtils.getEthUseDhcpOrStaticIp(activity);
+        Log.d("network", "get net type: " + type);
+        if (type == 1) {
+            //静态
+            network="STATIC";
+            network_two_tx.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+            network_one_tx.setBackgroundResource(R.drawable.selector_nuser_msg_tx_d);
+        } else if (type == 2) {
+            //动态
+            network="DHCP";
+            network_one_tx.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+            network_two_tx.setBackgroundResource(R.drawable.selector_nuser_msg_tx_d);
+        }
+
+        network_one_tx.setOnClickListener(v -> {
+            network="DHCP";
+            network_one_tx.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+            network_two_tx.setBackgroundResource(R.drawable.selector_nuser_msg_tx_d);
+        });
+        network_two_tx.setOnClickListener(v -> {
+            network="STATIC";
+            network_two_tx.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+            network_one_tx.setBackgroundResource(R.drawable.selector_nuser_msg_tx_d);
+        });
+        network_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+                //Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+                //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                //activity.startActivity(intent);
+
+                if (network.equals("STATIC")){
+                    Network2DialogHelper.showDialog(activity);
+                }else {
+                    //设置成动态获取网络
+                    if (EthernetUtils.setDynamicIp(activity)) {
+                        showMessage("Success");
+                    } else {
+                        showMessage("Failed");
+                    }
+                }
+
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+}

+ 64 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/RebootDialogHelper.java

@@ -0,0 +1,64 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory;
+import com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper;
+
+
+public class RebootDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+    public static void showDialog(Activity activity) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_restart_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        Button btn_cancel = contentView.findViewById(R.id.server_cancel_button);
+        Button server_determine_button = contentView.findViewById(R.id.server_determine_button);
+        btn_cancel.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+            }
+        });
+        server_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+                HardWareFactory.getHardTools().Registration(activity);
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+}

+ 75 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/ReinforcementsDialogHelper.java

@@ -0,0 +1,75 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+
+/**
+ * 增援提示
+ * */
+public class ReinforcementsDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+    public static void dismiss() {
+        if (alertDialog!=null){
+            alertDialog.dismiss();
+        }
+    }
+    public static void showDialog(Activity activity ,boolean type) {
+        if (alertDialog != null && alertDialog.isShowing()) {
+            return;
+        }
+        // 倒计时时间(单位:毫秒)
+        long countdownTime = 5000;
+
+        Handler handler = new Handler();
+        Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                if (alertDialog != null && alertDialog.isShowing()) {
+                    alertDialog.dismiss();
+                }
+            }
+        };
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_reinforcements_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        ImageView reinforcements_img = contentView.findViewById(R.id.reinforcements_img);
+        TextView reinforcements_tip_text = contentView.findViewById(R.id.reinforcements_tip_text);
+        Button reinforcements_confirm_button = contentView.findViewById(R.id.reinforcements_confirm_button);
+        if (type){
+            reinforcements_img.setBackgroundResource(R.mipmap.fachu);
+            reinforcements_tip_text.setText(R.string.reinforce_sent);
+            reinforcements_confirm_button.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+        }else {
+            reinforcements_img.setBackgroundResource(R.mipmap.xiangy);
+            reinforcements_tip_text.setText(R.string.reinforce_respond);
+            reinforcements_confirm_button.setBackgroundResource(R.drawable.shape_reinforcements_dialog_bt_bg);
+        }
+        reinforcements_confirm_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+                handler.removeCallbacks(runnable);  // 取消倒计时任务
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        alertDialog.setOnCancelListener(dialog -> {
+            // 用户点击对话框外部时,取消倒计时任务
+            handler.removeCallbacks(runnable);
+        });
+
+        handler.postDelayed(runnable, countdownTime);
+    }
+}

+ 94 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/ServicesDialogHelper.java

@@ -0,0 +1,94 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.utils.CommonUtils;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+public class ServicesDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+    public static void showDialog(final Activity activity, ClickListener clickListener) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_server_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog);
+        builder.setView(contentView);
+
+        Button server_determine_button = contentView.findViewById(R.id.server_determine_button);
+        Button server_cancel_button = contentView.findViewById(R.id.server_cancel_button);
+        LinearLayout layout = contentView.findViewById(R.id.ll_server_config_view);
+        EditText server_ed = contentView.findViewById(R.id.server_ed);
+        server_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                if(server_ed.getText().toString().equals("")){
+                    showMessage(R.string.str_server_ip_empty);
+                    return;
+                }
+
+                CommonUtils.setUrl(BaseApplication.appContext, server_ed.getText().toString());
+                if (clickListener != null) {
+                    String IP = server_ed.getText().toString();
+                    clickListener.onClick(IP);
+                }
+                alertDialog.dismiss();
+            }
+        });
+        server_cancel_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                server_ed.setText("");
+            }
+        });
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(alertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public interface ClickListener{
+        void onClick(String bedVO);
+    }
+}

+ 111 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/SystemDialogHelper.java

@@ -0,0 +1,111 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.zhyl.ZhylManager;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.activity.SystemActivity;
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory;
+import com.wdkl.app.ncs.callingbed.helper.Utils;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.utils.CommonUtils;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.push;
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+public class SystemDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+
+
+    public static void showDialog(Activity activity,int type) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_password_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        LinearLayout layout = contentView.findViewById(R.id.ll_password_view);
+        Button password_cancel_button = contentView.findViewById(R.id.password_cancel_button);
+        Button password_determine_button = contentView.findViewById(R.id.password_determine_button);
+        EditText password_ed = contentView.findViewById(R.id.password_ed);
+
+        layout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    Utils.hideInputKeyboard(alertDialog.getWindow().getDecorView().getWindowToken());
+                } catch (Exception e) {
+                    //
+                }
+            }
+        });
+
+        password_cancel_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+            }
+        });
+        password_determine_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                String passwprd =password_ed.getText().toString();
+                if (passwprd.equals("888")){
+                    if (type==1){
+                        Intent intent = new Intent();
+                        intent.setClass(activity, SystemActivity.class);
+                        activity.startActivity(intent);
+                    }else if (type==2){
+                        //打开底部导航栏
+                        HardWareFactory.getHardTools().startbar(true);
+                        Intent intent = new Intent(Settings.ACTION_SETTINGS);
+                        activity.startActivity(intent);
+
+                    }else {
+                        Intent intent = new Intent();
+                        intent.setClass(activity, SystemActivity.class);
+                        activity.startActivity(intent);
+                    }
+
+                } else {
+                    showMessage(R.string.invalid_password);
+                }
+                alertDialog.dismiss();
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 71 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/UpdataDialogHelper.java

@@ -0,0 +1,71 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.activity.AppUpdateActivity;
+
+
+public class UpdataDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+    public static void showDialog(Activity activity, ClickListener clickListener) {
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_version_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        TextView version_number_tx = contentView.findViewById(R.id.version_number_tx);
+        TextView version_time_tx = contentView.findViewById(R.id.version_time_tx);
+        Button version_button = contentView.findViewById(R.id.version_button);
+        version_number_tx.setText( BuildConfig.VERSION_NAME + "_" + BuildConfig.VERSION_CODE + "_" + Build.MODEL);
+        version_time_tx.setText(BuildConfig.BUILD_TIME);
+
+        version_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                clickListener.onClick();
+                alertDialog.dismiss();
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int screenWidth = metrics.widthPixels;
+        int orientation = activity.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT && screenWidth>600) {
+            try {
+                Window window = alertDialog.getWindow();
+                WindowManager.LayoutParams lp = window.getAttributes();
+                lp.width = 800;
+                lp.height = 650;
+                lp.gravity = Gravity.CENTER;
+                window.setAttributes(lp);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    public interface ClickListener{
+        void onClick();
+    }
+}

+ 79 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/dialog/WifiSetDialogHelper.java

@@ -0,0 +1,79 @@
+package com.wdkl.app.ncs.callingbed.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+
+/**
+ * 睡眠床垫配网 提示弹窗
+ * */
+public class WifiSetDialogHelper {
+
+    private static AlertDialog alertDialog;
+
+    public static void dismiss() {
+        if (alertDialog!=null){
+            alertDialog.dismiss();
+        }
+    }
+    public static void showDialog(Activity activity ,int type) {
+        if (alertDialog != null && alertDialog.isShowing()) {
+            return;
+        }
+        // 倒计时时间(单位:毫秒)
+        long countdownTime = 5000;
+
+        Handler handler = new Handler();
+        Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                if (alertDialog != null && alertDialog.isShowing()) {
+                    alertDialog.dismiss();
+                }
+            }
+        };
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.main_reinforcements_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        ImageView reinforcements_img = contentView.findViewById(R.id.reinforcements_img);
+        TextView reinforcements_tip_text = contentView.findViewById(R.id.reinforcements_tip_text);
+        Button reinforcements_confirm_button = contentView.findViewById(R.id.reinforcements_confirm_button);
+        if (type==1){
+            reinforcements_img.setBackgroundResource(R.mipmap.fachu);
+            reinforcements_tip_text.setText(R.string.ble_device_wifi_type_1);
+            reinforcements_confirm_button.setBackgroundResource(R.drawable.shape_main_hos_txt_bg);
+        }else if (type==2){
+            reinforcements_img.setBackgroundResource(R.mipmap.xiangy);
+            reinforcements_tip_text.setText(R.string.ble_device_wifi_type_2);
+            reinforcements_confirm_button.setBackgroundResource(R.drawable.shape_reinforcements_dialog_bt_bg);
+        }else if (type==3){
+            reinforcements_img.setBackgroundResource(R.mipmap.xiangy);
+            reinforcements_tip_text.setText(R.string.ble_device_wifi_type_3);
+            reinforcements_confirm_button.setBackgroundResource(R.drawable.shape_reinforcements_dialog_bt_bg);
+        }
+        reinforcements_confirm_button.setOnClickListener(v -> {
+            if (alertDialog != null && alertDialog.isShowing()) {
+                alertDialog.dismiss();
+                handler.removeCallbacks(runnable);  // 取消倒计时任务
+            }
+        });
+        alertDialog = builder.create();
+        alertDialog.setCanceledOnTouchOutside(true);
+        alertDialog.setCancelable(true);
+        alertDialog.show();
+        alertDialog.setOnCancelListener(dialog -> {
+            // 用户点击对话框外部时,取消倒计时任务
+            handler.removeCallbacks(runnable);
+        });
+
+        handler.postDelayed(runnable, countdownTime);
+    }
+}

+ 255 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/MainFragment.kt

@@ -0,0 +1,255 @@
+package com.wdkl.app.ncs.callingbed.fragment
+
+import android.text.TextUtils
+import android.view.View
+import androidx.recyclerview.widget.GridLayoutManager
+import com.enation.javashop.net.engine.model.NetState
+import com.google.gson.Gson
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.adapter.NurseConfigAdpter
+import com.wdkl.app.ncs.callingbed.databinding.MainViewLayoutBinding
+import com.wdkl.app.ncs.callingbed.helper.Utils
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.utils.*
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedMainFragmentContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedMainFragmentPresenter
+import com.wdkl.ncs.android.middleware.model.dos.EventDO
+import com.wdkl.ncs.android.middleware.model.dto.NurseConfigDto
+import com.wdkl.ncs.android.middleware.model.vo.CustomerInfoVO
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import com.wdkl.ncs.android.middleware.utils.StringUtil
+import kotlinx.android.synthetic.main.main_view_layout.*
+import kotlinx.android.synthetic.main.view_bed_name.tv_bed_name
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+/**
+ * 月子中心呼叫记录界面
+ */
+class  MainFragment: BaseFragment<BedMainFragmentPresenter, MainViewLayoutBinding>(), BedMainFragmentContract.View {
+    val TAG = "MainFragment"
+    private lateinit var nurseConfigAdpter: NurseConfigAdpter
+    private var clickTime: Long = 0
+    private var clickTimes: Int = 1
+
+    private val QR_CODE_URL2 = "http://n.szwdkl.cn?type=BIND_PART_AND_ADDR"
+
+    var controlIdArray = intArrayOf(R.id.bed_f_txt1, R.id.bed_f_txt2, R.id.bed_f_txt3, R.id.bed_f_txt4, R.id.bed_f_txt5, R.id.bed_f_txt6)
+
+    private var allOrders = ArrayList<NurseConfigDto>()
+
+    override fun getLayId(): Int {
+        return R.layout.main_view_layout
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        val layoutManager = GridLayoutManager(getActivity(), 3)
+        rv_main_view.setLayoutManager(layoutManager)
+        updateInfo()
+    }
+
+    override fun bindEvent() {
+        ll_bed.setOnClickListener {
+            val time = System.currentTimeMillis()
+            if (time - clickTime < 1500) {
+                clickTimes++
+            } else {
+                clickTimes = 1
+            }
+
+            if (clickTimes >15) {
+                showMessage("enable status bar")
+                Utils.hideStatusBar(activity, false)
+                clickTimes = 1
+            }
+            clickTime = time
+        }
+    }
+
+    override fun destory() {
+    }
+
+    override fun showCustomInfo(customInfo: CustomerInfoVO) {
+        if (Constant.convenientServiceEnabled) {
+            //便民服务二维码
+            Thread {
+                val builder = StringBuilder()
+                builder.append(QR_CODE_URL2)
+                builder.append("&no=")
+                builder.append(Constant.PART_UNION_ID)
+                builder.append("&page=shopping")
+                builder.append("&addr=")
+                builder.append(Constant.PART_NAME)
+                builder.append(Constant.BED_NAME)
+                val code = EcodeHelper().createQRImage(builder.toString(), 180, null)
+                activity.runOnUiThread {
+                    ll_qr_code?.visibility = View.VISIBLE
+                    image_qr_code?.setImageBitmap(code)
+                }
+            }.start()
+        } else {
+            ll_qr_code?.visibility = View.GONE
+        }
+
+        if (customInfo.memberId != null) {
+            Constant.MEMBER_ID = customInfo.memberId
+        }
+
+        //隐藏空页面并展示入住信息
+//        Constant.CUSTOM_INFO = Gson().toJson(customInfo)
+        //显示入住信息
+        tv_bed_name.text = customInfo.named
+        Constant.FJ_NAME =customInfo.named
+        if (customInfo.sex == 0) {
+            tv_bed_sex.setText(R.string.str_gender_female)
+            Constant.FJ_SEX = getString(R.string.str_female)
+        } else if (customInfo.sex == 1) {
+            tv_bed_sex.setText(R.string.str_gender_male)
+            Constant.FJ_SEX = getString(R.string.str_male)
+        }
+        tv_bed_age.text = getString(R.string.str_age) + customInfo.age + customInfo.ageUnit
+        Constant.FJ_AGE =""+customInfo.age + customInfo.ageUnit
+        if (customInfo.inDate != null) {
+            tv_bed_time.text = StringUtil.getResString(R.string.indate) + TimeHandle.getDateTime(customInfo.inDate * 1000, "yyyy.MM.dd")
+        }
+        if (!TextUtils.isEmpty(customInfo.cardNo)) {
+            tv_bed_code.text = StringUtil.getResString(R.string.card_no) + customInfo.cardNo
+        }
+
+//        if (TextUtils.isEmpty(customInfo.advice)) {
+//            tv_order_content.text = StringUtil.getResString(R.string.str_empty)
+//        } else {
+//            tv_order_content.text = customInfo.advice
+//        }
+
+        if (Constant.doctorValid == 1) {
+            bed_medic_info.text = Constant.doctorTitle
+            bed_medic_name.text = customInfo.doctorName
+        } else {
+            bed_medic_name.text = StringUtil.getResString(R.string.str_empty)
+        }
+
+        if (Constant.nurseValid == 1) {
+            bed_medic_info2.text = Constant.nurseTitle
+            bed_medic_name2.text = customInfo.nurseName
+        } else {
+            bed_medic_name2.text = StringUtil.getResString(R.string.str_empty)
+        }
+
+        //更新护理项
+        if (customInfo.list != null ) {
+            rv_main_view_s.visibility =View.GONE
+            rv_main_view_ll.visibility =View.VISIBLE
+            updateMoreConfigs(customInfo.list)
+        }else {
+            rv_main_view_ll.visibility =View.GONE
+            rv_main_view_s.visibility =View.VISIBLE
+        }
+    }
+
+    override fun showEvents(data: ArrayList<EventDO>) {
+
+    }
+
+    override fun onError(message: String, type: Int) {
+        showMessage(message)
+    }
+
+    override fun onNoNet() {
+        showMessage("none network")
+    }
+
+    override fun complete(message: String, type: Int) {
+    }
+
+    override fun start() {
+    }
+
+    override fun networkMonitor(state: NetState) {
+        state.filter(onWifi = {
+
+        }, onMobile = {
+
+        }, offline = {
+
+        })
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
+    private fun updateInfo() {
+        tv_bed_name.setText(R.string.str_empty)
+        tv_bed_age.setText(R.string.str_age)
+        tv_bed_sex.setText(R.string.str_gender_none)
+        tv_bed_code.setText(R.string.card_no)
+        tv_bed_time.setText(R.string.indate)
+        if (Constant.DEVICE_STATUS == 0) {
+            tv_bed_name_title.setText(R.string.str_empty)
+        } else {
+            tv_bed_name_title.text =CommonUtils.subStringAfter2(Constant.BED_NAME, "-")
+        }
+
+        if (Constant.CUSTOM_ID != -1) {
+            presenter.loadCustomInfo(Constant.CUSTOM_ID)
+        }
+
+        if (Constant.DEVICE_ID != -1) {
+            ll_qr_code.visibility = View.VISIBLE
+        }
+    }
+
+    private fun updateMoreConfigs(data: List<NurseConfigDto>) {
+
+           allOrders.clear()
+
+           for ((index, e) in data.withIndex()) {
+
+                if (e.isBool_critical!=null && e.nurseOptionName!=null)   {
+                    if (e.isBool_critical && e.nurseOptionName.equals("病重")){
+                        main_view_bg.setBackgroundResource(R.mipmap.bingren_bg_hh)
+                    }else if (e.isBool_critical && e.nurseOptionName.equals("病危")){
+                        main_view_bg.setBackgroundResource(R.mipmap.bingren_bg_h)
+                    }
+                }
+               if (e.nurseOptionName!=null){
+                   allOrders.add(e)
+               }
+               nurseConfigAdpter = NurseConfigAdpter(activity, allOrders)
+               rv_main_view.adapter = nurseConfigAdpter
+               nurseConfigAdpter.updateData(allOrders)
+
+        }
+
+//        for (i in data.indices) {
+//            if (i >= controlIdArray.size) break // 如果控件数量不足,则提前结束循环
+//            val textView: TextView = view!!.findViewById<TextView>(controlIdArray[i])
+//            textView.text = data[i].nurseOptionName
+//        }
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        when (messageEvent.getType()) {
+            Constant.EVENT_UPDATE_CUSTOM -> {
+                updateInfo()
+            }
+        }
+    }
+}

+ 365 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/SleepDataTableFragment.kt

@@ -0,0 +1,365 @@
+package com.wdkl.app.ncs.callingbed.fragment
+
+
+import android.graphics.Color
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import android.widget.TextView
+import com.enation.javashop.net.engine.model.NetState
+import com.github.mikephil.charting.data.Entry
+import com.google.gson.FieldNamingPolicy
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.SleepDataTableFragmentLayBinding
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.utils.SleepLineChartUtils2
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.core.locale.SettingConfigNew
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedSignFragmentContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedSignFragmentPresenter
+import com.wdkl.ncs.android.middleware.model.vo.BedSleepDataVo
+import com.wdkl.ncs.android.middleware.model.vo.BedSleepVo
+import com.wdkl.ncs.android.middleware.model.vo.SingDataBean
+import kotlinx.android.synthetic.main.sleep_data_table_fragment_lay.*
+import okhttp3.FormBody
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.util.*
+import java.util.concurrent.TimeUnit
+import kotlin.collections.ArrayList
+
+/**
+ * 体征数据表格
+ * */
+class SleepDataTableFragment : BaseFragment<BedSignFragmentPresenter, SleepDataTableFragmentLayBinding>(), BedSignFragmentContract.View {
+
+    var state :String=""
+    private val TAG = "SleepDataTableFragment"
+    private var allOrders = ArrayList<BedSleepVo>()
+
+    private var lineChartUtils: SleepLineChartUtils2? = null
+
+    private val list = ArrayList<Entry>() //数据集合
+
+    var qualified_Number :Int =0
+
+    var sn :String =""
+
+
+    override fun getLayId(): Int {
+        val currentLanguage: String = Locale.getDefault().getLanguage()
+        if (currentLanguage.equals("es")){
+            return R.layout.sleep_data_table_fragment_lay_es
+        }else{
+
+            return R.layout.sleep_data_table_fragment_lay
+        }
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        state = requireArguments().getString("state").toString()
+            if (BuildConfig.sleep_type == "1") {
+                if (!state.equals("")){
+//                    emptyImageView.visibility= View.GONE
+//                    sleep_bg_sl.visibility= View.VISIBLE
+                    checkServer()
+                }
+//                else{
+//                    emptyImageView.visibility= View.VISIBLE
+//                    sleep_bg_sl.visibility= View.GONE
+//                }
+            }else if (BuildConfig.sleep_type == "3"){
+                if (!Constant.sleep_sn .equals("")){
+//                    emptyImageView.visibility= View.GONE
+//                    sleep_bg_sl.visibility= View.VISIBLE
+                    checkServer()
+                }
+//                else{
+//                    emptyImageView.visibility= View.VISIBLE
+//                    sleep_bg_sl.visibility= View.GONE
+//                }
+            }
+
+
+
+
+    }
+
+    private fun checkServer() {
+        Thread {
+                val okHttpClient = OkHttpClient().newBuilder()
+                        .connectTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .readTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .writeTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                        .build()
+//            val baseUrl: String ="http://192.168.1.199:7000/xiaomian/get_new_list_by_sn"
+            if (BuildConfig.sleep_type == "1") {
+                 sn = state // 请替换为实际的 SN 值
+            }else if (BuildConfig.sleep_type == "3"){
+                 sn = Constant.sleep_sn // 请替换为实际的 SN 值
+            }
+                val reportTime = -1
+//                val url = "$baseUrl?sn=$sn&reportTime=$reportTime"
+               val baseUrl: String ="https://api.base.wdklian.com/xiaomian/get_new_list_by_sn"
+
+            val requestBody = FormBody.Builder()
+                    .add("sn", sn)
+                    .add("reportTime", reportTime.toString())
+                    .build()
+
+                val request = Request.Builder()
+                        .url(baseUrl)
+                        .post(requestBody)
+                        .build()
+
+                try {
+                    Log.i(TAG, "start check server: $baseUrl")
+                    val response = okHttpClient.newCall(request).execute()
+                    if (response != null && response.isSuccessful) {
+                        //接口数据获取成功,检查设备是否已注册
+                        val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                        val itemType = object : TypeToken<ArrayList<BedSleepVo>>(){}.type
+                        allOrders = gson.fromJson<ArrayList<BedSleepVo>>(response.body()?.string(), itemType)
+                        Log.e(TAG, "check server exception:" + allOrders.toString())
+                        initView(1)
+                    } else {
+                        //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                        initView(2)
+                    }
+                } catch (e: Exception) {
+                    initView(2)
+                    //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                    Log.e(TAG, "check server exception:")
+                    e.printStackTrace()
+                }
+        }.start()
+    }
+    private fun initView(type: Int) {
+        val handler = Handler(Looper.getMainLooper())
+        handler.post {
+            // 在这里执行与UI元素相关的操作
+            try {
+                if (type==1){
+                        if (allOrders!=null && allOrders.size>0){
+                            var size :Int = 0
+                            size = allOrders.indices.maxByOrNull { allOrders[it].total_duration }!!
+
+                            sleep_time_z_tx1.text=convertToTime(allOrders.get(size).total_duration)
+                            sleep_time_tx1.text=allOrders.get(size).gobed_time+"~"+allOrders.get(size).outbed_time
+                            sleep_bg_state_number.text=allOrders.get(size).score_value.toString()
+
+                            sleep_time_s_tx1.text=allOrders.get(size).gobed_time
+                            sleep_time_zc_tx1.text=convertToTime(allOrders.get(size).in_duration)
+                            sleep_time_sssz_tx1.text=convertToTime(allOrders.get(size).deep_duration)
+
+                            val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                            val itemType = object : TypeToken<BedSleepDataVo>(){}.type
+                            val DataList = gson.fromJson<BedSleepDataVo>(allOrders.get(size).report_content, itemType)
+
+                            sleep_bg_state.setviewText(DataList.score.state.toString())
+                            //香睡指数
+                            sleep_bg_state_number.setColorBasedOnValue2(DataList.score.state, 1)
+                            //睡眠效率
+                            sleep_time_smxl_img.setColorBasedOnValue(DataList.sleep_eff.state, 2)
+                            //心率
+                            sleep_time_pjhs_img.setColorBasedOnValue(DataList.avg_rh.state, 2)
+                            //体动
+                            sleep_time_wsts_img.setColorBasedOnValue(DataList.move_count.state, 2)
+                            //打鼾
+                            sleep_time_dhcs_img.setColorBasedOnValue(DataList.snoring_count.state, 2)
+                            //离床
+                            sleep_time_lccs_img.setColorBasedOnValue(DataList.outbed_count.state, 2)
+
+
+                            sleep_time_td_tx1.text = getString(R.string.str_times, DataList.dt_arr.size)
+
+                            //打鼾次数
+                            sleep_time_dhcs_tx1.text = countOnes(DataList.snoring_arr)
+
+                            //离床次数
+                            sleep_time_lccs_tx1.text = countOnes(DataList.outbed_arr)
+
+                            sleep_time_smxl_tx1.text = DataList.sleep_eff.value.toString()
+
+                            sleep_time_pjhs_tx1.text = getString(R.string.str_times_per_min, DataList.avg_rh.value)
+
+                            if (qualified_Number==0){
+                                sleep_time_wsts_tx1.setText(R.string.sleep_qualified)
+                            }else{
+                                sleep_time_wsts_tx1.text = getString(R.string.sleep_unqualified, qualified_Number)
+                            }
+                            var maxValue_list = Integer.MIN_VALUE
+                            var latestValue_list = Integer.MAX_VALUE
+                            for (i in 0 until DataList.rh_arr.size) {
+                                val heartRate = DataList.rh_arr[i]
+                                maxValue_list = Math.max(maxValue_list, heartRate)
+                                latestValue_list = Math.min(latestValue_list, heartRate)
+                                list?.add(Entry(i.toFloat(), DataList.rh_arr[i].toFloat()))
+                            }
+                            lineChartUtils = SleepLineChartUtils2(
+                                    list,
+                                    null,
+                                    maxValue_list,
+                                    latestValue_list,
+                                    sleep_dtat_chart)
+                            emptyImageView.visibility= View.GONE
+                            sleep_bg_sl.visibility= View.VISIBLE
+                        }else{
+                            emptyImageView.visibility= View.VISIBLE
+                            sleep_bg_sl.visibility= View.GONE
+                        }
+
+                }else{
+                    emptyImageView.visibility= View.VISIBLE
+                    sleep_bg_sl.visibility= View.GONE
+                }
+            } catch (e: Exception) {
+                initView(2)
+            }
+        }
+
+    }
+
+    fun View.setColorBasedOnValue(value: Int, type: Int) {
+        //只改变字体颜色
+        if (type==1){
+            when (value) {
+                1 -> qualified_Number += 1
+                in 3..Int.MAX_VALUE -> setBackgroundColor(Color.GREEN)
+                2 -> setBackgroundColor(Color.YELLOW)
+                1 -> setBackgroundColor(Color.RED)
+                else -> setBackgroundColor(Color.GREEN)
+            }
+        }else if (type==2){
+            //改变图标
+            when (value) {
+                1 -> qualified_Number += 1
+                in 3..Int.MAX_VALUE -> setBackgroundResource(R.drawable.xuanzl)
+                2 -> setBackgroundResource(R.drawable.xuanzy)
+                1 -> setBackgroundResource(R.drawable.xuanzh)
+                else -> setBackgroundResource(R.drawable.xuanzl)
+            }
+        }
+    }
+
+    fun TextView.setColorBasedOnValue2(value: Int, type: Int) {
+        //只改变字体颜色
+            when (value) {
+                1 -> qualified_Number += 1
+                in 3..Int.MAX_VALUE -> setTextColor(Color.GREEN)
+                2 -> setTextColor(Color.YELLOW)
+                1 -> setTextColor(Color.RED)
+                else -> setTextColor(Color.GREEN)
+            }
+
+    }
+    fun TextView.setviewText(value: String) {
+        //只改变字体颜色
+        when (value) {
+            "1" -> setText(R.string.str_sleep_poor2)
+            "2" -> setText(R.string.str_sleep_poor)
+            "3" -> setText(R.string.str_sleep_poor3)
+            "4" -> setText(R.string.str_sleep_poor4)
+        }
+
+    }
+
+
+
+    /**
+     * 时间转时间和分钟
+     */
+     fun convertToTime(minutes: Int): String {
+        val hours = minutes / 60
+        val remainingMinutes = minutes % 60
+        return getString(R.string.str_hour_min, hours, remainingMinutes)
+    }
+    fun countOnes(arr: List<Int>): String {
+        var count = 0
+        for (i in arr.indices) {
+            if (arr[i] == 1) {
+                count++
+            }
+        }
+
+        return getString(R.string.str_times, count)
+    }
+    override fun bindEvent() {
+        //
+    }
+
+    override fun destory() {
+        //
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        if (Constant.EVENT_SING_TYPE == messageEvent.type) {
+            if (allOrders != null) {
+//                if (allOrders.get(type).log_list!=null) {
+//                    emptyImageView.visibility= View.GONE
+//                } else {
+//                    emptyImageView.visibility= View.VISIBLE
+//                }
+            }
+        }
+    }
+
+
+
+
+
+    override fun onError(message: String, type: Int) {
+        showMessage(message)
+    }
+
+    override fun showsigns(advices: ArrayList<SingDataBean>) {
+
+    }
+
+
+    override fun onNoNet() {
+        showMessage("none network")
+    }
+
+    override fun complete(message: String, type: Int) {
+    }
+
+    override fun start() {
+    }
+
+    override fun networkMonitor(state: NetState) {
+        state.filter(onWifi = {
+
+        }, onMobile = {
+
+        }, offline = {
+
+        })
+    }
+}

+ 255 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/SleepGraphOfCurveFragment.kt

@@ -0,0 +1,255 @@
+package com.wdkl.app.ncs.callingbed.fragment
+
+import android.util.Log
+import android.view.View
+import com.enation.javashop.net.engine.model.NetState
+import com.github.mikephil.charting.data.Entry
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.databinding.SleepGraphCurveFragmentLayBinding
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.app.ncs.callingbed.utils.SleepLineChartUtils
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedSignFragmentContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedSignFragmentPresenter
+import com.wdkl.ncs.android.middleware.model.vo.SingDataBean
+import kotlinx.android.synthetic.main.sign_graph_curve_fragment_lay.*
+import kotlinx.android.synthetic.main.sleep_graph_curve_fragment_lay.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+
+class SleepGraphOfCurveFragment : BaseFragment<BedSignFragmentPresenter, SleepGraphCurveFragmentLayBinding>(), BedSignFragmentContract.View {
+
+
+    private val TAG = "SignGraphOfCurveFragment"
+    private var allOrders = ArrayList<SingDataBean>()
+    var type:Int=0
+    var state :String=""
+
+    var slepp_data_lin :String=""
+
+    private val list = ArrayList<Entry>() //数据集合
+
+    private val list1 =ArrayList<Entry>() //数据集合
+
+    val heartRateList = ArrayList<Int>()
+    val breathRateList = ArrayList<Int>()
+
+
+    private var lineChartUtils: SleepLineChartUtils? = null
+
+//    private var lineChartUtils2: SleepLineChartUtils? = null
+
+
+    override fun getLayId(): Int {
+        return R.layout.sleep_graph_curve_fragment_lay
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+
+    override fun init() {
+        state = requireArguments().getString("states").toString()
+        sleep_graph_emptyImageView.visibility= View.VISIBLE
+    }
+
+    private fun initView() {
+
+    }
+
+
+    //设置顶部线条颜色
+    private fun setlindata() {
+        list.clear()
+        list1.clear()
+        if (heartRateList.size!=null || breathRateList.size!=null ) {
+            if (lineChartUtils==null ){
+                var maxValue_list = Integer.MIN_VALUE
+                var latestValue_list = Integer.MAX_VALUE
+                var maxValue_list1  = Integer.MIN_VALUE
+                var latestValue_list1  = Integer.MAX_VALUE
+                for (i in 0 until heartRateList.size) {
+                    val heartRate = heartRateList[i]
+                    maxValue_list = Math.max(maxValue_list, heartRate)
+                    latestValue_list = Math.min(latestValue_list, heartRate)
+                    list?.add(Entry(i.toFloat(), heartRateList[i].toFloat()))
+                }
+                for (i in 0 until breathRateList.size) {
+                    val heartRate = heartRateList[i]
+                    maxValue_list1 = Math.max(maxValue_list1, heartRate)
+                    latestValue_list1 = Math.min(latestValue_list1, heartRate)
+                    list1?.add(Entry(i.toFloat(), breathRateList[i].toFloat()))
+                }
+
+                lineChartUtils = SleepLineChartUtils(
+                        list,
+                        list1,
+                        maxValue_list,
+                        latestValue_list1,
+                        sleep_chart)
+
+//                lineChartUtils2 = SleepLineChartUtils(
+//                        list1,
+//                        maxValue_list1,
+//                        latestValue_list1,
+//                        sleep_chart2)
+
+            }else{
+//                lineChartUtils!!.createLineChartUtils()
+//                lineChartUtils2!!.createLineChartUtils()
+                var maxValue_list = Integer.MIN_VALUE
+                var latestValue_list = Integer.MAX_VALUE
+                var maxValue_list1  = Integer.MIN_VALUE
+                var latestValue_list1  = Integer.MAX_VALUE
+                for (i in 0 until heartRateList.size) {
+                    val heartRate = heartRateList[i]
+                    maxValue_list = Math.max(maxValue_list, heartRate)
+                    latestValue_list = Math.min(latestValue_list, heartRate)
+                    list?.add(Entry(i.toFloat(), heartRateList[i].toFloat()))
+                }
+                for (i in 0 until breathRateList.size) {
+                    val heartRate = heartRateList[i]
+                    maxValue_list1 = Math.max(maxValue_list1, heartRate)
+                    latestValue_list1 = Math.min(latestValue_list1, heartRate)
+                    list1?.add(Entry(i.toFloat(), breathRateList[i].toFloat()))
+                }
+//                Log.d("LineChartUtils", "list size: " + xdata.size);
+                lineChartUtils!!.updateData(list, list1, maxValue_list, latestValue_list1, sleep_chart)
+//                lineChartUtils2!!.updateData(list1, maxValue_list1, latestValue_list1, chart)
+            }
+        }else{
+            lineChartUtils!!.createLineChartUtils();
+//            lineChartUtils2!!.createLineChartUtils();
+            sign_graph_emptyImageView.visibility= View.VISIBLE
+        }
+
+
+
+    }
+
+
+    override fun bindEvent() {
+        //
+    }
+
+    override fun destory() {
+        //
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
+
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        if (Constant.EVENT_SLEEP_TYPE == messageEvent.type) {
+            Log.d("传递参数", "数据1:" + messageEvent.slepp_data + "数据2" + messageEvent.slepp_data_lin)
+            sleep_graph_emptyImageView.visibility= View.GONE
+            if(messageEvent.slepp_data_lin!=null){
+                slepp_data_lin= messageEvent.slepp_data_lin
+                if (BuildConfig.sleep_type == "1") {
+                    SleppDataLinDataParsing(slepp_data_lin)
+                }else if (BuildConfig.sleep_type == "3"){
+                    SleppwifiDataLinDataParsing(slepp_data_lin)
+                }
+                setlindata()
+            }else{
+                sleep_graph_emptyImageView.visibility= View.VISIBLE
+            }
+            //            Thread.sleep(5000)
+        }
+    }
+    //床垫波形串口数据解析
+    private fun SleppDataLinDataParsing(data: String) {
+        heartRateList.clear()
+        breathRateList.clear()
+        for (i in 0 until data.length step 8) {
+            val heartRateHex = data.substring(i, i + 2)
+            val breathRateHex = data.substring(i + 4, i + 6)
+            val heartRateDecimal = heartRateHex.toInt(16)
+            val breathRateDecimal = breathRateHex.toInt(16)
+            heartRateList.add(heartRateDecimal)
+            breathRateList.add(breathRateDecimal)
+        }
+//       Log.d("传递参数", "数据1:" + heartRateList.toString() )
+//        Log.d("传递参数", "数据2:" + breathRateList.toString() )
+    }
+
+    //床垫波形WIFI数据解析
+    private fun SleppwifiDataLinDataParsing(data: String) {
+        heartRateList.clear()
+        breathRateList.clear()
+        var size =data.length/4
+        for (i in 0 until size ) {
+            val j = i * 4
+            val s1 = data.substring(j, j + 2)
+            val s2 = data.substring(j + 2, j + 4)
+            val value = Integer.parseInt(s2 + s1, 16)
+            if (i % 2 == 0) {
+                heartRateList.add(value)
+            } else {
+                breathRateList.add(value)
+            }
+        }
+//       Log.d("传递参数", "数据1:" + heartRateList.toString() )
+//        Log.d("传递参数", "数据2:" + breathRateList.toString() )
+    }
+
+
+    override fun onError(message: String, type: Int) {
+        showMessage(message)
+    }
+
+    override fun showsigns(advices: ArrayList<SingDataBean>) {
+//        if (advices!=null){
+//            allOrders.clear()
+//            allOrders=advices
+//            if (allOrders.get(type).log_list !=null) {
+//                sign_graph_emptyImageView.visibility= View.GONE
+//                setlindata()
+//            } else {
+//                sign_graph_emptyImageView.visibility= View.VISIBLE
+//            }
+//        }else{
+//            showMessage("数据为空")
+//        }
+
+    }
+
+    override fun onNoNet() {
+        showMessage("none network")
+    }
+
+    override fun complete(message: String, type: Int) {
+    }
+
+    override fun start() {
+    }
+
+
+
+    override fun networkMonitor(state: NetState) {
+        state.filter(onWifi = {
+
+        }, onMobile = {
+
+        }, offline = {
+
+        })
+    }
+}

+ 335 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/apartmentFragment.kt

@@ -0,0 +1,335 @@
+package com.wdkl.app.ncs.callingbed.fragment
+
+import android.content.Intent
+import android.view.View
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.app.ncs.callingbed.BuildConfig
+import com.wdkl.app.ncs.callingbed.R
+import com.wdkl.app.ncs.callingbed.activity.DeviceLinkageActivity
+import com.wdkl.app.ncs.callingbed.activity.SleepMonitoringActivity
+import com.wdkl.app.ncs.callingbed.adapter.NurseConfigAdpter
+import com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil
+import com.wdkl.app.ncs.callingbed.databinding.MainView3LayoutBinding
+import com.wdkl.app.ncs.callingbed.dialog.SystemDialogHelper
+import com.wdkl.app.ncs.callingbed.helper.NetHelper
+import com.wdkl.app.ncs.callingbed.helper.Utils
+import com.wdkl.app.ncs.callingbed.launch.CallingbedLaunch
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.vo.filter
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.logic.contract.callingbed.BedMainFragmentContract
+import com.wdkl.ncs.android.middleware.logic.presenter.callingbed.BedMainFragmentPresenter
+import com.wdkl.ncs.android.middleware.model.dos.EventDO
+import com.wdkl.ncs.android.middleware.model.dto.NurseConfigDto
+import com.wdkl.ncs.android.middleware.model.vo.CustomerInfoVO
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import kotlinx.android.synthetic.main.main_view3_layout.*
+import kotlinx.android.synthetic.main.main_view_layout.*
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import serialporttest.utils.SerialPortUtilCBDbed
+import serialporttest.utils.SerialPortUtilSofa
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
+/**
+ * 公寓首页
+ * */
+class  apartmentFragment: BaseFragment<BedMainFragmentPresenter, MainView3LayoutBinding>(), BedMainFragmentContract.View {
+    val TAG = "MainFragment"
+    private lateinit var nurseConfigAdpter: NurseConfigAdpter
+    private var clickTime: Long = 0
+    private var clickTimes: Int = 1
+
+    private val QR_CODE_URL2 = "http://n.szwdkl.cn?type=BIND_PART_AND_ADDR"
+
+    var controlIdArray = intArrayOf(R.id.bed_f_txt1, R.id.bed_f_txt2, R.id.bed_f_txt3, R.id.bed_f_txt4, R.id.bed_f_txt5, R.id.bed_f_txt6)
+
+    private var allOrders = ArrayList<NurseConfigDto>()
+
+    var ip : String = ""
+    var port : String = ""
+    override fun getLayId(): Int {
+        return R.layout.main_view3_layout
+    }
+
+    override fun bindDagger() {
+        CallingbedLaunch.component.inject(this)
+    }
+    val scheduler = Executors.newScheduledThreadPool(1)
+    override fun init() {
+//        val layoutManager = GridLayoutManager(getActivity(), 3)
+//        rv_main_view.setLayoutManager(layoutManager)
+        updateInfo()
+        // 定义要执行的任务
+        val task = Runnable {
+            val bedStatus = getStatus(Constant.CBD_ld_bed, Constant.CBD_ld_bed_2)
+            val sofaStatus = getStatus(Constant.CBD_ld_sofa, Constant.CBD_ld_sofa_2)
+            val sleepStatus = getStatus(Constant.CBD_ld_sleep, Constant.CBD_ld_sleep_2)
+
+            activity.runOnUiThread {
+                main_view3_tv_bed_time.text = "设备状态: 律动床垫: $bedStatus 律动床椅: $sofaStatus 睡眠床垫: $sleepStatus"
+            }
+
+        }
+        scheduler.scheduleAtFixedRate(task, 0, 20, TimeUnit.SECONDS)
+    }
+
+    override fun bindEvent() {
+        main_view3_ll_bed.setOnClickListener {
+            val time = System.currentTimeMillis()
+            if (time - clickTime < 1500) {
+                clickTimes++
+            } else {
+                clickTimes = 1
+            }
+
+            if (clickTimes >15) {
+                showMessage("enable status bar")
+                Utils.hideStatusBar(activity, false)
+                clickTimes = 1
+            }
+            clickTime = time
+        }
+        //体征
+        main_view3_bed_f_txt1.setOnClickListener {
+            SystemDialogHelper.showDialog(activity, 1)
+        }
+        //睡眠监测
+        main_view3_bed_f_txt2.setOnClickListener {
+            val intent = Intent()
+            intent.setClass(activity, SleepMonitoringActivity::class.java)
+            activity.startActivity(intent)
+        }
+        //联动设备
+        main_view3_bed_f_txt3.setOnClickListener {
+            val intent = Intent()
+            intent.setClass(activity, DeviceLinkageActivity::class.java)
+            activity.startActivity(intent)
+        }
+        //律动床垫--开关
+        main_view3_bed_f_txt4.setOnClickListener {
+            //f1 律动床垫 f2 律动椅子
+            SerialPortUtilCBDbed.getInstance().sendCommand("01")
+        }
+        //律动床椅--开关
+        main_view3_bed_f_txt5.setOnClickListener {
+            //f1 律动床垫 f2 律动椅
+            SerialPortUtilSofa.getInstance().sendCommand("01","FF")
+        }
+        //
+        main_view3_bed_f_txt6.setOnClickListener {
+
+        }
+
+    }
+    // 封装设备状态描述的函数
+    fun getStatus(isActive: Boolean, isUploading: Boolean): String {
+        return when {
+            isActive && isUploading -> "设备开启, 数据上传中"
+            isActive -> "设备开启, 数据未上传"
+            else -> "设备关闭, 数据未上传"
+        }
+    }
+    override fun destory() {
+    }
+
+    override fun showCustomInfo(customInfo: CustomerInfoVO) {
+
+        main_view3_ll_qr_code?.visibility = View.GONE
+        if (customInfo.memberId != null) {
+            Constant.MEMBER_ID = customInfo.memberId
+        }
+        //隐藏空页面并展示入住信息
+//        Constant.CUSTOM_INFO = Gson().toJson(customInfo)
+        //显示入住信息
+        main_view3_tv_bed_name.text = customInfo.named
+
+        Constant.FJ_NAME =customInfo.named
+
+        Constant.FJ_AGE =""+customInfo.age + customInfo.ageUnit
+
+        main_view3_tv_bed_code.text ="IP地址:"+ NetHelper.getInstance().localIP
+        main_view3_tv_bed_age.text ="MAC地址:"+ Constant.DEVICE_REGISTER_ID
+
+                if (!BuildConfig.DEBUG) {
+                    ip = Constant.SLEEP_TCP_SERVER_URL
+                    port = Constant.SLEEP_TCP_PORT.toString()
+                } else {
+                    ip = Constant.SLEEP_TCP_SERVER_URL_TXT
+                    port = Constant.SLEEP_TCP_PORT.toString()
+                }
+        if (Constant.Sleep_TCP_CONNECTED){
+            main_view3_tv_bed_sex.text ="数据服务器状态: 地址"+ip+" 端口:"+port+"连接正常"
+        }else{
+            main_view3_tv_bed_sex.text ="数据服务器状态:  地址"+ip+" 端口:"+port+"连接失败,重新连接中"
+        }
+        main_view3_tv_bed_time.text ="设备状态: 律动床垫:"+"律动床椅:"+"睡眠床垫:"
+
+
+
+        main_view3_rv_main_view_s.visibility =View.VISIBLE
+    }
+
+    override fun showEvents(data: ArrayList<EventDO>) {
+
+    }
+
+    override fun onError(message: String, type: Int) {
+        showMessage(message)
+    }
+
+    override fun onNoNet() {
+        showMessage("none network")
+    }
+
+    override fun complete(message: String, type: Int) {
+    }
+
+    override fun start() {
+    }
+
+    override fun networkMonitor(state: NetState) {
+        state.filter(onWifi = {
+
+        }, onMobile = {
+
+        }, offline = {
+
+        })
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        scheduler.shutdownNow()
+        super.onStop()
+    }
+
+    private fun updateInfo() {
+        main_view3_tv_bed_name.setText(R.string.str_empty)
+        main_view3_tv_bed_age.setText(R.string.str_age)
+        main_view3_tv_bed_sex.setText(R.string.str_gender_none)
+        main_view3_tv_bed_code.setText(R.string.card_no)
+        main_view3_tv_bed_time.setText(R.string.indate)
+        if (Constant.DEVICE_STATUS == 0) {
+            main_view3_tv_bed_name_title.setText(R.string.str_empty)
+        } else {
+            main_view3_tv_bed_name_title.text =CommonUtils.subStringAfter(Constant.BED_NAME, "-")
+        }
+
+        if (Constant.CUSTOM_ID != -1) {
+            presenter.loadCustomInfo(Constant.CUSTOM_ID)
+        }
+
+        if (Constant.DEVICE_ID != -1) {
+            main_view3_ll_qr_code.visibility = View.VISIBLE
+        }
+
+    }
+
+    private fun updateMoreConfigs(data: List<NurseConfigDto>) {
+           allOrders.clear()
+
+           for ((index, e) in data.withIndex()) {
+
+                if (e.isBool_critical!=null && e.nurseOptionName!=null)   {
+                    if (e.isBool_critical && e.nurseOptionName.equals("病重")){
+                        main_view_bg.setBackgroundResource(R.mipmap.bingren_bg_hh)
+                    }else if (e.isBool_critical && e.nurseOptionName.equals("病危")){
+                        main_view_bg.setBackgroundResource(R.mipmap.bingren_bg_h)
+                    }
+                }
+               if (e.nurseOptionName!=null){
+                   allOrders.add(e)
+               }
+               nurseConfigAdpter = NurseConfigAdpter(activity, allOrders)
+               rv_main_view.adapter = nurseConfigAdpter
+               nurseConfigAdpter.updateData(allOrders)
+
+        }
+
+//        for (i in data.indices) {
+//            if (i >= controlIdArray.size) break // 如果控件数量不足,则提前结束循环
+//            val textView: TextView = view!!.findViewById<TextView>(controlIdArray[i])
+//            textView.text = data[i].nurseOptionName
+//        }
+    }
+
+    //心率
+    var heartRate :Int=0
+    //读取呼吸率
+    var breathingRate  :Int=0
+//    //状态
+//    var status_int  :Int=0
+//    //状态
+//    var status  :String=""
+//    //电池电量
+//    var batteryLevel  : String=""
+//    // 读取监测带 SN
+//    var monitorSN  : String=""
+
+    var slepp_data :String=""
+    //床垫数据解析
+    private fun SleppDataDataParsing(data: String) {
+        try {
+            heartRate = BluetoothUtil.hexToDecimal(data.substring(0, 2))
+            main_view3_bed_medic_name.text = heartRate.toString()+getString(R.string.str_breathe_nuber)
+            breathingRate = BluetoothUtil.hexToDecimal(data.substring(2, 4))
+            main_view3_bed_medic_name2.text = breathingRate.toString()+getString(R.string.str_breathe_nuber)
+        } catch (e: Exception) {
+
+        }
+//        status_int = BluetoothUtil.hexToDecimal(data.substring(4, 6))
+//        if( status_int == 3){
+//            status = getString(R.string.str_in_bed)
+//        }else  if( status_int == 4){
+//            status = getString(R.string.str_out_bed)
+//        }else  if( status_int == 5){
+//            status = getString(R.string.str_snore)
+//        }else  if( status_int == 6){
+//            status = getString(R.string.str_body_move)
+//        }
+//        sleep_bed_type.text =" 心率:"+heartRate+" 次/分 呼吸"+breathingRate+"次/分 当前状态:"+status
+//        sleep_bed_type.text = getString(R.string.str_sleep_status, status)
+//        if (data.substring(6, 8).equals("64")){
+//            batteryLevel ="100%"
+//        }
+//        type = data.substring(8, 20)
+//        monitorSN="SN:"+data.substring(8, 20)
+//        if (sleep_bed_sn.text.equals("")){
+//            sleep_bed_sn.text =monitorSN
+//        }
+
+
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+        when (messageEvent.getType()) {
+            Constant.EVENT_UPDATE_CUSTOM -> {
+                updateInfo()
+            }
+            Constant.EVENT_SLEEP_tcp -> {
+                if (Constant.Sleep_TCP_CONNECTED) {
+                    main_view3_tv_bed_sex.text = "数据服务器状态: 连接成功"
+                } else {
+                    main_view3_tv_bed_sex.text = "数据服务器状态: 连接失败,重新连接中"
+                }
+            }
+            Constant.EVENT_SLEEP_DATA -> {
+                if (messageEvent.slepp_data != null) {
+                    slepp_data = messageEvent.slepp_data
+                    SleppDataDataParsing(slepp_data)
+                }
+            }
+        }
+    }
+}

+ 65 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/HardTools.java

@@ -0,0 +1,65 @@
+package com.wdkl.app.ncs.callingbed.hardware;
+
+
+import android.app.Application;
+import android.content.Context;
+
+import com.wdkl.app.ncs.callingbed.activity.AppUpdateActivity;
+import com.wdkl.app.ncs.callingbed.activity.CallingbedActivationActivity;
+import com.wdkl.app.ncs.callingbed.activity.CallingbedActivity;
+
+
+public  class HardTools {
+
+    public HardTools() {
+
+    }
+    //初始化
+    public void init(CallingbedActivationActivity callingbedActivationActivity){}
+    //退出
+    public void unInit(){}
+    //是否卸载旧版本
+    public void uninstallApp(Context context , boolean isuninstall, String name){}
+    //串口设置
+    public void setSerial(CallingbedActivity callingbedActivity){}
+    //检查launch版本
+    public void checkLaunch(){}
+    //紧急按钮Start
+    public void setSOSStart(){}
+    //紧急按钮Stop
+    public void setSOSStop(){}
+    //门灯颜色
+    public void setDoorLight(int type){}
+    //重置设备
+    public void resetDevice(){}
+    //重置设备 XCrashUtils
+    public void resetDevicex(Application application){}
+    //注册方式
+    public void Registration(Context context ){}
+    //安装方式1
+    public void installApk(AppUpdateActivity context ){}
+    //安装方式2
+    public void startInstallApk(AppUpdateActivity context ){}
+
+    public void CallConfigg(int mic,int yl){}
+
+    public void startbar(Boolean is){}
+    public void setTime(Context context , long timeMills, String timeZone){}
+
+
+    //提供卡号
+    public  void offerCardData(String data){}
+    //提供按键数据
+    public void offerKeyBoardData(String data){}
+    //是否开启灯光
+    public  void enableLed(boolean isEnable){}
+
+    public  void enableIRLed(boolean isEnable){}
+
+    public  void enableControlLed(boolean isEnable,int id){}
+    //麦克风
+    public void enalbeNet(boolean isEnable){}
+    //设置voip 初始化配置
+    public void setVoipConfig(){}
+
+}

+ 25 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/HardWareFactory.java

@@ -0,0 +1,25 @@
+package com.wdkl.app.ncs.callingbed.hardware;
+
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.app.ncs.callingbed.hardware.imp.LGCBDHardTools;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+/**
+ * 硬件设备控制适配类
+ *
+ * **/
+public  class HardWareFactory {
+    //不同硬件设备控制类替换即可
+    private static HardTools hardTools;
+    public static HardTools getHardTools() {
+        if(null == hardTools) {
+             if(BuildConfig.flag.equals(Constant.DEV_W_LG_CBD)) {
+                hardTools = new LGCBDHardTools();
+            }
+        }
+        return hardTools ;
+    }
+
+
+}

+ 186 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/imp/LGCBDHardTools.java

@@ -0,0 +1,186 @@
+package com.wdkl.app.ncs.callingbed.hardware.imp;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.app.ncs.callingbed.activity.AppUpdateActivity;
+import com.wdkl.app.ncs.callingbed.activity.CallingbedActivationActivity;
+import com.wdkl.app.ncs.callingbed.activity.CallingbedActivity;
+import com.wdkl.app.ncs.callingbed.hardware.HardTools;
+import com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper;
+import com.wdkl.app.ncs.callingbed.helper.NetHelper;
+import com.wdkl.app.ncs.callingbed.helper.SOSHelper;
+import com.wdkl.app.ncs.callingbed.settings.SettingConfig;
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.ncs.android.middleware.utils.AppUtil;
+import com.xbh.sdk4.client.UserAPI;
+import com.xbh.sdk4.database.DatabaseHelper;
+import com.xbh.sdk4.system.SystemHelper;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import serialporttest.utils.SerialPortUtil;
+import serialporttest.utils.SerialPortUtil433;
+
+/**
+ * 普威硬件控制类
+ *
+ * */
+public class LGCBDHardTools extends HardTools {
+
+    public static final String HARDWDT_SERVICE = "LGCBDHardTools";
+    private Application app;
+
+
+    private static class YldHardToolsHolder{
+        private final  static LGCBDHardTools lgcbdHardTools = new LGCBDHardTools();
+    }
+
+    public static LGCBDHardTools getInstance(){
+        return YldHardToolsHolder.lgcbdHardTools;
+    }
+
+    @Override
+    public void init(CallingbedActivationActivity callingbedActivationActivity) {
+        if (Boolean.parseBoolean(BuildConfig.open_sleep)){
+            SettingConfig.setSLEEPGatewayOn(callingbedActivationActivity, true);
+        }
+
+    }
+
+    @Override
+    public void unInit() {
+
+    }
+    @Override
+    public void startbar(Boolean is) {
+        super.startbar(is);
+    }
+
+    @Override
+    public void resetDevice() {
+
+    }
+    @Override
+    public void resetDevicex(Application application) {
+        SystemHelper mSystemHelper = new SystemHelper();
+        mSystemHelper.reboot();
+    }
+    @Override
+    public void Registration(Context context) {
+        //获取mac地址
+
+        UserAPI.getInstance().init(context);
+        SystemHelper mSystemHelper = new SystemHelper();
+        if (mSystemHelper.getSerialNum().isEmpty()){
+            Constant.LOCAL_MAC = NetHelper.getInstance().getIMEI();
+        }else {
+            Constant.LOCAL_MAC =mSystemHelper.getSerialNum();
+        }
+        Constant.DEVICE_REGISTER_ID = Constant.LOCAL_MAC;
+        //开机自启动
+        DatabaseHelper.setSystemProperties("persist.sys.bootApk","com.wdkl.app.ncs.callingbed2");
+//        //守护进程
+        DatabaseHelper.setSystemProperties("persist.lgo.nooperateStartPkg","com.wdkl.app.ncs.callingbed2");
+        DatabaseHelper.setSystemProperties("persist.lgo.keepNopAliveTimeSec","10");
+         Log.e("wdkl_app", " app getStringSystemProperties: " +   DatabaseHelper.getStringSystemProperties("persist.lgo.nooperateStartPkg","com.wdkl.app.ncs.callingbed2"));
+        //设置导航栏状态栏隐藏
+
+    }
+    @Override
+    public void setTime(Context context, long timeMills, String timeZone)  {
+        try {
+            if (timeMills==0)return;
+            SystemHelper mSystemHelper = new SystemHelper();
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(new Date(timeMills));
+            int year = calendar.get(Calendar.YEAR);
+            int month = calendar.get(Calendar.MONTH) + 1;
+            int day = calendar.get(Calendar.DAY_OF_MONTH);
+            int hour = calendar.get(Calendar.HOUR_OF_DAY);
+            int minute = calendar.get(Calendar.MINUTE);
+            int second = calendar.get(Calendar.SECOND);
+//            Log.e("wdkl_app", " app setTime: " + year+month+day+hour+minute+second);
+            mSystemHelper.setTime(year, month, day, hour, minute, second); //设置时间为 2021/08/10 13:05:00
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        super.setTime(context, timeMills, timeZone);
+    }
+
+    @Override
+    public void setSerial(CallingbedActivity callingbedActivity) {
+    }
+
+    @Override
+    public void uninstallApp(Context context, boolean isuninstall, String name) {
+        //卸载原来二代系统apk
+        if (isuninstall) {
+            Thread thread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    // 在子线程中执行的代码
+                    if (checkAppExist(context,name)) {
+                        AppUtil.uninstallApp(name);
+                    }
+                }
+            });
+        }
+    }
+
+    @Override
+    public void setSOSStart() {
+        SOSHelper.sosStart();
+    }
+
+    @Override
+    public void setSOSStop() {
+        SOSHelper.sosStop();
+    }
+    @Override
+    public void setDoorLight(int type) {
+//        if (type==1){
+//            //绿色
+//            SerialPortHelper.setDoorLight(1, Constant.nursingColor);
+//        }else if (type==2){
+//            //白色
+//            SerialPortHelper.setDoorLight(1, "111"); //白色
+//        }else if (type==3){
+//            //红色
+//            SerialPortHelper.setDoorLight(1, "200"); //红色闪烁
+//        }else if (type==4){
+//            //红色
+//            SerialPortHelper.setDoorLight(0, "000"); //关闭
+//        }
+    }
+
+    @Override
+    public void installApk(AppUpdateActivity context) {
+    }
+
+    @Override
+    public void startInstallApk(AppUpdateActivity context) {
+
+    }
+
+    private boolean checkAppExist(Context context, String name) {
+        PackageManager packageManager = context.getPackageManager();
+        List<PackageInfo> packageInfoList = packageManager.getInstalledPackages(0);
+        boolean appExist = false;
+        for (PackageInfo pInfo : packageInfoList) {
+            if (name.equals(pInfo.packageName)) {
+                appExist = true;
+                break;
+            }
+        }
+        Log.e("wdkl_app", "callingdoor app exist: " + appExist);
+        return appExist;
+    }
+}

+ 14 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AlarmMessageUtil.java

@@ -0,0 +1,14 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+public class AlarmMessageUtil {
+
+    public static String getAlarmMessage(String cmd){
+        //----> ffcc020006b50831
+        StringBuilder sb = new StringBuilder();
+        sb.append("ffcc02");
+        sb.append(String.format("%04X",cmd.length()));
+        sb.append(cmd);
+        return sb.toString();
+    }
+
+}

+ 252 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AnrFcExceptionUtil.java.bak

@@ -0,0 +1,252 @@
+package com.wdkl.app.ncs.callingbed2.helper;
+
+import android.app.AlarmManager;
+import android.app.Application;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Environment;
+import android.util.Log;
+
+import com.github.anrwatchdog.ANRError;
+import com.github.anrwatchdog.ANRWatchDog;
+import com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity;
+import com.wdkl.ncs.android.middleware.api.UrlManager;
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.skywebrtc.CallSession;
+import com.wdkl.skywebrtc.EnumType;
+import com.wdkl.skywebrtc.SkyEngineKit;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.FormBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * Created by dengzhe on 2018/4/2.
+ * //=========================FC&ANR异常处理类=========================//
+ */
+
+public class AnrFcExceptionUtil implements Thread.UncaughtExceptionHandler {
+
+    private static ANRWatchDog mANRWatchDog;
+    private Thread.UncaughtExceptionHandler mDefaultHandler;
+    public static final String TAG = "MyApplication";
+    private static Application application;
+
+    private static AnrFcExceptionUtil mAnrFcExceptionUtil;
+
+    private OkHttpClient okHttpClient;
+    private UrlManager urlManager = UrlManager.Companion.build();
+
+    /**
+     * 存储异常和参数信息
+     */
+    private Map<String, String> paramsMap = new HashMap<>();
+    /**
+     * 格式化时间
+     */
+    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
+
+
+    public static AnrFcExceptionUtil getInstance(Application application) {
+        if (mAnrFcExceptionUtil == null) {
+            mAnrFcExceptionUtil = new AnrFcExceptionUtil(application);
+        }
+        return mAnrFcExceptionUtil;
+    }
+
+    private AnrFcExceptionUtil(Application application) {
+        //获取系统默认的UncaughtException处理器
+        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+        this.application = application;
+    }
+
+    @Override
+    public void uncaughtException(Thread thread, Throwable ex) {
+        if (!handleException(ex) && mDefaultHandler != null) {
+            //如果用户没有处理则让系统默认的异常处理器来处理
+            mDefaultHandler.uncaughtException(thread, ex);
+        } else {
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "error : ", e);
+            }
+
+            restartApp();
+        }
+    }
+
+    private void restartApp() {
+        Constant.CALL_STATE = Constant.CALL_STANDBY;
+        CallSession session= SkyEngineKit.Instance().getCurrentSession();
+        if(session!=null&&session.getState()!= EnumType.CallState.Idle){
+            SkyEngineKit.Instance().endCall();
+        }
+
+        //重新启动app
+        Intent mStartActivity = new Intent(application.getApplicationContext(), WelcomeActivity.class);
+        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        int mPendingIntentId = 123456;
+        PendingIntent mPendingIntent = PendingIntent.getActivity(application.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+        AlarmManager mgr = (AlarmManager) application.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1500, mPendingIntent);
+
+        android.os.Process.killProcess(android.os.Process.myPid());
+        System.exit(0);
+    }
+
+    /**
+     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
+     *
+     * @param ex
+     * @return true:如果处理了该异常信息;否则返回false.
+     */
+    private boolean handleException(Throwable ex) {
+        if (ex == null) {
+            return false;
+        }
+        //使用Toast来显示异常信息
+        /*new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+//                Toast.makeText(application.getApplicationContext(), "很抱歉,程序出现异常,即将重新启动.",
+//                        Toast.LENGTH_SHORT).show();
+                Looper.loop();
+            }
+        }.start();*/
+        saveCrashInfo2File(ex);
+        return true;
+    }
+
+    /**
+     * 保存错误信息到文件中
+     *
+     * @param ex
+     * @return 返回文件名称
+     */
+    private String saveCrashInfo2File(Throwable ex) {
+        StringBuffer sb = new StringBuffer();
+        for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            sb.append(key + "=" + value + "\n");
+        }
+
+        Writer writer = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(writer);
+        ex.printStackTrace(printWriter);
+        Throwable cause = ex.getCause();
+        while (cause != null) {
+            cause.printStackTrace(printWriter);
+            cause = cause.getCause();
+        }
+        printWriter.close();
+        String result = writer.toString();
+        sb.append(result);
+
+        try {
+            long timestamp = System.currentTimeMillis();
+            format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
+            String time = format.format(new Date());
+            String fileName = "crash-" + time + "-" + timestamp + ".txt";
+            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+                String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crash/";
+                File dir = new File(path);
+                if (!dir.exists()) {
+                    dir.mkdirs();
+                }
+                FileOutputStream fos = new FileOutputStream(path + fileName);
+                fos.write(sb.toString().getBytes());
+                Log.i(TAG, "saveCrashInfo2File: "+sb.toString());
+                fos.close();
+            }
+
+            //上传错误日志
+            uploadingErrorLog(application.getPackageName(), "crash", "crash", "", sb.toString());
+
+            return fileName;
+        } catch (Exception e) {
+            Log.e(TAG, "an error occured while writing file...", e);
+        }
+        return null;
+    }
+
+    private void uploadingErrorLog(String class_name, String err_msg, String exception_name, String method_name, String stack_trace) {
+        if(okHttpClient == null){
+            okHttpClient = new OkHttpClient();
+        }
+
+        FormBody.Builder formBody = new FormBody.Builder();
+        formBody.add("class_name",class_name);
+        formBody.add("method_name",method_name);
+        formBody.add("exception_name",exception_name);
+        formBody.add("err_msg",err_msg);
+        formBody.add("stack_trace",stack_trace);
+
+        Request request  = new Request.Builder()
+                .url(urlManager.getBase() + "device/error_log")
+                .post(formBody.build())
+                .build();
+
+        okHttpClient.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                Log.e(TAG,"错误日志上传失败"+e.getMessage());
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+                Log.d(TAG,"错误日志上传成功");
+                String data = response.body().string();
+                Log.d(TAG,"错误日志数据 data "+data);
+            }
+        });
+    }
+
+    /**
+     * ===================================================崩溃异常处理===================================================
+     */
+    public void initFCException() {
+        //设置该CrashHandler为程序的默认处理器
+        AnrFcExceptionUtil catchExcep = AnrFcExceptionUtil.getInstance(application);
+        Thread.setDefaultUncaughtExceptionHandler(catchExcep);
+        mANRWatchDog = new ANRWatchDog(8000);
+        mANRWatchDog.setInterruptionListener(new ANRWatchDog.InterruptionListener() {
+            @Override
+            public void onInterrupted(InterruptedException exception) {
+            }
+        }).setIgnoreDebugger(true).setANRListener(new ANRWatchDog.ANRListener() {
+            @Override
+            public void onAppNotResponding(ANRError error) {
+                /*Intent mStartActivity = new Intent(application.getApplicationContext(), Constants.ANR_FC);
+                int mPendingIntentId = 123456;
+                PendingIntent mPendingIntent = PendingIntent.getActivity(application.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+                AlarmManager mgr = (AlarmManager) application.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+                mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1500, mPendingIntent);
+                android.os.Process.killProcess(android.os.Process.myPid());*/
+
+                Log.d("anr", "Anr restart app...");
+                AppUpdateHelper.reboot(application);
+            }
+        }).start();
+
+    }
+}

+ 305 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AppUpdateHelper.java

@@ -0,0 +1,305 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.zhyl.ZhylManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+
+import android.util.Log;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import androidx.core.content.FileProvider;
+
+public class AppUpdateHelper {
+    private final static String TAG = "AppUpdate";
+
+    /**
+     * 下载的APK文件绝对路径
+     */
+    public static final String FILE_APK_PATH = Environment.getExternalStorageDirectory() + "/CallingBed2";
+    /**
+     * 下载的APK文件的文件名
+     */
+    public static final String FILE_APK_NAME = "CallingBed2APK.apk";
+
+    public static void installAPK(Context context) {
+        try {
+            File apkFile = new File(FILE_APK_PATH + "/" + FILE_APK_NAME);
+            if (!apkFile.exists()) {
+                return;
+            }
+
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//安装完成后打开新版本
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 给目标应用一个临时授权
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//判断版本大于等于7.0
+                //如果SDK版本>=24,即:Build.VERSION.SDK_INT >= 24,使用FileProvider兼容安装apk
+                String packageName = context.getApplicationContext().getPackageName();
+                String authority = new StringBuilder(packageName).append(".fileprovider").toString();
+                Uri apkUri = FileProvider.getUriForFile(context, authority, apkFile);
+                intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
+            } else {
+                intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
+            }
+            context.startActivity(intent);
+        } catch (Exception e) {
+        }
+    }
+
+    public static void updateApp(Context context, UpdateCallBack callBack) {
+        if (checkApkExit(context)) {
+            Log.d(TAG, "文件存在");
+        } else {
+            Log.d(TAG, "文件不存在");
+            if (callBack != null) {
+                callBack.onFailed();
+            }
+            return;
+        }
+
+        String path = FILE_APK_PATH + "/" + FILE_APK_NAME;
+        if (rootInstall(context, context.getPackageName(), path)) {
+            Log.d(TAG, "安装成功");
+            if (callBack != null) {
+                callBack.onSuccess();
+            }
+        } else {
+            Log.d(TAG, "安装失败");
+            if (callBack != null) {
+                callBack.onFailed();
+            }
+        }
+    }
+    public static void updateAppA133(Context context, UpdateCallBack callBack) {
+        if (checkApkExit(context)) {
+            Log.d(TAG, "文件存在");
+        } else {
+            Log.d(TAG, "文件不存在");
+            if (callBack != null) {
+                callBack.onFailed();
+            }
+            return;
+        }
+
+        String path = FILE_APK_PATH + "/" + FILE_APK_NAME;
+        ZhylManager zhylManager = ZhylManager.getInstance(context);
+        zhylManager.sys_doSilentInstallApp(path, context);
+
+        /*zhylManager.sys_doSilentInstallAppObserver(path, new IAppInstallObserver() {
+            @Override
+            public void onInstallFinished(String s, int i, String s1) throws RemoteException {
+                Log.d(TAG, "install result: " + s);
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        });*/
+    }
+
+    private static boolean checkApkExit(Context context) {
+        File file = new File(FILE_APK_PATH + "/" + FILE_APK_NAME);
+        return file.exists();
+    }
+
+    private static boolean checkApkAvailable(Context context, String path) {
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo info = pm.getPackageArchiveInfo(path, 0);
+            ApplicationInfo applicationInfo = info.applicationInfo;
+            String newPkg = applicationInfo.packageName;
+            String curPkg = context.getPackageName();
+            Log.d(TAG, "new package: " + newPkg + ", cur package: " + curPkg);
+            if (curPkg.equals(newPkg)) {
+                return true;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return false;
+    }
+
+    public static boolean silentInstall(Context context, String apkPath) {
+        PackageManager packageManager = context.getPackageManager();
+        Class pmClz = packageManager.getClass();
+        try {
+            if (Build.VERSION.SDK_INT >= 21) {
+                Log.d(TAG, "apk path: " + apkPath);
+                Class aClass = Class.forName("android.app.PackageInstallObserver");
+                Constructor constructor = aClass.getDeclaredConstructor();
+                constructor.setAccessible(true);
+                Object installObserver = constructor.newInstance();
+                Method method = pmClz.getDeclaredMethod("installPackage", Uri.class, aClass, int.class, String.class);
+                method.setAccessible(true);
+                method.invoke(packageManager, Uri.fromFile(new File(apkPath)), installObserver, 2, null);
+            } else {
+                Method method = pmClz.getDeclaredMethod("installPackage", Uri.class, Class.forName("android.content.pm.IPackageInstallObserver"), int.class, String.class);
+                method.setAccessible(true);
+                method.invoke(packageManager, Uri.fromFile(new File(apkPath)), null, 2, null);
+            }
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, e.toString());
+        }
+        return false;
+    }
+
+    public static boolean rootInstall(Context context, String packageName, String path) {
+        Process process;
+        PrintWriter printWriter;
+        BufferedReader errorStream = null;
+        BufferedReader successStream = null;
+        Boolean result;
+        try {
+            process = Runtime.getRuntime().exec(AppUtil.DEFAULT_SU_PATH);
+            printWriter = new PrintWriter(process.getOutputStream());
+            printWriter.println("pm install -i "+packageName+" -r " + path);//-i "+packageName+"
+            printWriter.flush();
+            printWriter.close();
+            Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
+            PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+            AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0及以上
+                mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 45000, restartIntent);
+            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 4.4及以上
+                mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 45000, restartIntent);
+            }
+            int value = process.waitFor();
+            result = (value == 0);
+        } catch (Exception e) {
+            if(errorStream!=null){
+                try {
+                    errorStream.close();
+                } catch (IOException ioException) {
+                    ioException.printStackTrace();
+                }
+            }
+            if(successStream!=null){
+                try {
+                    successStream.close();
+                } catch (IOException ioException) {
+                    ioException.printStackTrace();
+                }
+            }
+            Log.e(TAG, "rootSilenceInstall e:" + e.getMessage());
+            result = false;
+        }
+
+        if(result) { //静默安装成功
+            Log.i(TAG,"静默安装成功!");
+            rootStartApk("com.wdkl.app.ncs.callingbed2","com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity");
+        }
+
+        return result;
+    }
+
+    public static boolean rootStartApk(String packageName,String activityName){
+        boolean isSuccess = false;
+        String cmd = "su am start -n " + packageName + "/" + activityName + " \n";
+        Process process = null;
+        try {
+            process = Runtime.getRuntime().exec(cmd);
+            int value = process.waitFor();
+            return value == 0;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally{
+            if(process!=null){
+                process.destroy();
+            }
+        }
+        return isSuccess;
+    }
+
+    public static boolean rootSilenceInstall(String path) {
+        Process process;
+        PrintWriter printWriter;
+        try {
+            Log.d(TAG, "install path: " + path);
+            process = Runtime.getRuntime().exec(AppUtil.DEFAULT_SU_PATH);
+            printWriter = new PrintWriter(process.getOutputStream());
+            printWriter.println("pm install -r " + path);
+            printWriter.flush();
+            printWriter.close();
+            int res = process.waitFor();
+            Log.e(TAG, "silent install res: " + res);
+            if (res == 0) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "rootSilenceInstall e:" + e.getMessage());
+            return false;
+        }
+    }
+
+    public static void reboot(Context context) {
+        Log.e("reboot","重启");
+        if (Build.MODEL.equals("rk3128")) {
+            try {
+                SerialPortHelper.resetDevice();
+                Intent intent = new Intent(Intent.ACTION_REBOOT);
+                intent.putExtra("nowait", 1);
+                intent.putExtra("interval", 1);
+                intent.putExtra("window", 0);
+                context.sendBroadcast(intent);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            Process process;
+            PrintWriter printWriter;
+            try {
+                process = Runtime.getRuntime().exec(AppUtil.DEFAULT_SU_PATH);
+                printWriter = new PrintWriter(process.getOutputStream());
+                printWriter.println("reboot");
+                printWriter.flush();
+                printWriter.close();
+                process.waitFor();
+            } catch (Exception e) {
+                e.printStackTrace();
+                restartApp(context);
+            }
+        }
+    }
+
+    public static void restartApp(Context context) {
+        //重新启动app
+        Intent mStartActivity = new Intent(context.getApplicationContext(), WelcomeActivity.class);
+        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        int mPendingIntentId = 123456;
+        PendingIntent mPendingIntent = PendingIntent.getActivity(context.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+        AlarmManager mgr = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1500, mPendingIntent);
+
+        android.os.Process.killProcess(android.os.Process.myPid());
+        System.exit(0);
+    }
+
+    public interface UpdateCallBack {
+        void onFailed();
+        void onSuccess();
+    }
+}

+ 121 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AppUtil.java

@@ -0,0 +1,121 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+
+public class AppUtil {
+
+    public static final String DEFAULT_SU_PATH = "su";
+
+    /**
+     * 设置系统时间
+     *
+     * @param time
+     */
+    public static void setSysTime(String time, String timeZone) {
+        try {
+            Process process = Runtime.getRuntime().exec(DEFAULT_SU_PATH);
+            if (null == process) return;
+            DataOutputStream os = new DataOutputStream(process.getOutputStream());
+            //os.writeBytes("setprop persist.sys.timezone Asia/Shanghai\n");
+            os.writeBytes("setprop persist.sys.timezone " + timeZone + "\n");
+            if (android.os.Build.VERSION.SDK_INT >= 24) {//7.1以上的系统
+                String datetime = changeTimeForm(time); //20211213:092314  ------  051315372019.00
+                os.writeBytes("/system/bin/date " + datetime + " set\n");
+            } else {
+                os.writeBytes("/system/bin/date -s " + time + "\n");//【时间格式 yyyyMMdd.HHmmss】"20131023.112800"
+            }
+            os.writeBytes("clock -w\n");
+            os.writeBytes("exit\n");
+            os.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static String changeTimeForm(String t) {
+        if (!TextUtils.isEmpty(t) && t.length() >= 15) {
+            String yyyy = substringByLengh(t, 0, 4);
+            String MMdd = substringByLengh(t, 4, 8);
+            String HHmm = substringByLengh(t, 9, 13);
+            String ss = substringByLengh(t, 13, 15);
+
+            return MMdd + HHmm + yyyy + "." + ss;
+        } else {
+            return "051315372019.00";
+        }
+    }
+
+    /**
+     * 字符串按索引截取
+     *
+     * @param str
+     * @return
+     */
+    public static String substringByLengh(String str, int start, int end) {
+        if (str == null) {
+            return "";
+        }
+        if (start > end) {
+            return "";
+        }
+        if (str.length() - 1 < start || str.length() < end) {
+            return "";
+        }
+
+        return str.substring(start, end);
+    }
+
+
+    public static void setSystemTime(Context context, int year, int month, int day, int hour, int minute, int mill) {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month);
+        c.set(Calendar.DAY_OF_MONTH, day);
+        c.set(Calendar.HOUR_OF_DAY, hour);
+        c.set(Calendar.MINUTE, minute);
+        c.set(Calendar.SECOND, mill);
+        c.set(Calendar.MILLISECOND, 0);
+        long when = c.getTimeInMillis();
+        if (when / 1000 < Integer.MAX_VALUE) {
+            ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when);
+        }
+    }
+
+    public static void setSystemTime(Context context, long timeMills, String timeZone) {
+        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        //alarmManager.setTimeZone("Asia/Shanghai");
+        alarmManager.setTimeZone(timeZone);
+        alarmManager.setTime(timeMills);
+    }
+
+    //开启网络调试
+    public static boolean openNetworkDebug() {
+        try {
+            Process process = Runtime.getRuntime().exec(DEFAULT_SU_PATH);
+            if (null == process) {
+                return false;
+            }
+            DataOutputStream os = new DataOutputStream(process.getOutputStream());
+            os.writeBytes("setprop service.adb.tcp.port 5555\n");
+            os.writeBytes("stop adbd\n");
+            os.writeBytes("start adbd\n");
+            os.writeBytes("exit\n");
+            os.flush();
+            Constant.OPEN_DEBUG = true;
+
+            return true;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return false;
+    }
+}

+ 187 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/AsyncPlayer.java

@@ -0,0 +1,187 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.LinkedList;
+
+/**
+ * 响铃相关类
+ */
+public class AsyncPlayer {
+    private static final int PLAY = 1;
+    private static final int STOP = 2;
+    private AudioManager audioManager;
+
+    private static final class Command {
+        int code;
+        Context context;
+        int resId;
+        boolean looping;
+        int stream;
+        long requestTime;
+
+        public String toString() {
+            return "{ code=" + code + " looping=" + looping + " stream=" + stream + " resId=" + resId + " }";
+        }
+    }
+
+    private final LinkedList mCmdQueue = new LinkedList();
+
+    private void startSound(Command cmd) {
+
+        try {
+            //MediaPlayer player = new MediaPlayer();
+            MediaPlayer player = MediaPlayer.create(cmd.context, cmd.resId);
+            player.setAudioStreamType(cmd.stream);
+            //player.setDataSource(cmd.context, cmd.uri);
+            player.setLooping(cmd.looping);
+            player.setVolume(1.0f, 1.0f);
+            //player.prepare();
+            player.start();
+            if (mPlayer != null) {
+                mPlayer.release();
+            }
+            mPlayer = player;
+            Log.w(mTag, "start sound " + cmd.resId);
+        } catch (Exception e) {
+            Log.w(mTag, "error loading sound for " + cmd.resId, e);
+        }
+    }
+
+    private final class Thread extends java.lang.Thread {
+        Thread() {
+            super("AsyncPlayer-" + mTag);
+        }
+
+        public void run() {
+            while (true) {
+                Command cmd = null;
+
+                synchronized (mCmdQueue) {
+
+                    cmd = (Command) mCmdQueue.removeFirst();
+                }
+
+                switch (cmd.code) {
+                    case PLAY:
+                        startSound(cmd);
+                        break;
+                    case STOP:
+
+                        if (mPlayer != null) {
+                            mPlayer.stop();
+                            mPlayer.reset();
+                            mPlayer.release();
+                            mPlayer = null;
+                        } else {
+                            Log.w(mTag, "STOP command without a player");
+                        }
+                        break;
+                }
+
+                synchronized (mCmdQueue) {
+                    if (mCmdQueue.size() == 0) {
+
+                        mThread = null;
+                        releaseWakeLock();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    private String mTag;
+    private Thread mThread;
+    private MediaPlayer mPlayer;
+    private PowerManager.WakeLock mWakeLock;
+
+    private int mState = STOP;
+
+    public AsyncPlayer(String tag) {
+        if (tag != null) {
+            mTag = tag;
+        } else {
+            mTag = "AsyncPlayer";
+        }
+    }
+
+    public void play(Context context, int res, boolean looping, int stream) {
+        Command cmd = new Command();
+        cmd.requestTime = SystemClock.uptimeMillis();
+        cmd.code = PLAY;
+        cmd.context = context;
+        cmd.resId = res;
+        cmd.looping = looping;
+        cmd.stream = stream;
+        synchronized (mCmdQueue) {
+            enqueueLocked(cmd);
+            mState = PLAY;
+        }
+    }
+
+    public void stop() {
+        synchronized (mCmdQueue) {
+            if (mState != STOP) {
+                Command cmd = new Command();
+                cmd.requestTime = SystemClock.uptimeMillis();
+                cmd.code = STOP;
+                enqueueLocked(cmd);
+                mState = STOP;
+            }
+        }
+    }
+
+    private void enqueueLocked(Command cmd) {
+        mCmdQueue.add(cmd);
+        if (mThread == null) {
+            acquireWakeLock();
+            mThread = new Thread();
+            mThread.start();
+        }
+    }
+
+    public void setUsesWakeLock(Context context) {
+        if (mWakeLock != null || mThread != null) {
+            throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock + " mThread=" + mThread);
+        }
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
+    }
+
+    private void acquireWakeLock() {
+        if (mWakeLock != null) {
+            mWakeLock.acquire();
+        }
+    }
+
+    private void releaseWakeLock() {
+        if (mWakeLock != null) {
+            mWakeLock.release();
+        }
+    }
+
+    private boolean isHeadphonesPlugged(Context context) {
+        if (audioManager == null) {
+            audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        }
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+            AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
+            for (AudioDeviceInfo deviceInfo : audioDevices) {
+                if (deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
+                        || deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
+                    return true;
+                }
+            }
+            return false;
+        } else {
+            return audioManager.isWiredHeadsetOn();
+        }
+    }
+}

+ 83 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/CallDialogHelper.java

@@ -0,0 +1,83 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.media.AudioManager;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+public class CallDialogHelper {
+
+    private static AlertDialog callDialog;
+
+    private static AsyncPlayer ringPlayer;
+
+    public static void showCallDialog(Activity activity, int callType, View.OnClickListener hangupCall, View.OnClickListener acceptCall, View.OnClickListener rejectCall) {
+        if (ringPlayer == null) {
+            ringPlayer = new AsyncPlayer(null);
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.call_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        LinearLayout outCall = contentView.findViewById(R.id.ll_call_outgoing);
+        ImageView hangup = contentView.findViewById(R.id.iv_hangup_call);
+
+        RelativeLayout inCall = contentView.findViewById(R.id.rl_call_incoming);
+        ImageView accept = contentView.findViewById(R.id.iv_accept_call);
+        ImageView reject = contentView.findViewById(R.id.iv_reject_call);
+
+        if (callType == 0) {
+            //去电
+            outCall.setVisibility(View.VISIBLE);
+            inCall.setVisibility(View.GONE);
+            ringPlayer.play(activity, R.raw.ring_back2, true, AudioManager.STREAM_MUSIC);
+        } else {
+            //来电
+            outCall.setVisibility(View.GONE);
+            inCall.setVisibility(View.VISIBLE);
+            ringPlayer.play(activity, R.raw.ring_tone, true, AudioManager.STREAM_MUSIC);
+        }
+
+        hangup.setOnClickListener(hangupCall);
+        accept.setOnClickListener(acceptCall);
+        reject.setOnClickListener(rejectCall);
+
+        callDialog = builder.create();
+        callDialog.setCanceledOnTouchOutside(false);
+        callDialog.setCancelable(false);
+        callDialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = callDialog.getWindow();
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 800;
+            lp.height = 400;
+            lp.gravity = Gravity.CENTER;
+            //lp.alpha = 0.4f;
+            //window.setBackgroundDrawableResource(R.color.transparent_dialog);
+            window.setAttributes(lp);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismissCallDialog() {
+        if (callDialog != null && callDialog.isShowing()) {
+            callDialog.dismiss();
+        }
+        if (ringPlayer != null) {
+            ringPlayer.stop();
+        }
+    }
+}

+ 24 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/CommonDialogHelper.java

@@ -0,0 +1,24 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import com.enation.javashop.utils.base.R.style;
+
+import com.enation.javashop.utils.base.widget.LoadingDialog;
+import com.enation.javashop.utils.base.widget.LoadingDialogImpl;
+
+public class CommonDialogHelper {
+
+    public static LoadingDialog createLoadingDialog(Context context, int layoutid, int imageviewid, boolean cancel) {
+        View localView = LayoutInflater.from(context).inflate(layoutid, (ViewGroup)null);
+        ImageView view = (ImageView)localView.findViewById(imageviewid);
+        LoadingDialogImpl localLoadingDialog = LoadingDialogImpl.getInstance(context, style.loading_dialog, view);
+        localLoadingDialog.setCancelable(cancel);
+        localLoadingDialog.setCanceledOnTouchOutside(cancel);
+        localLoadingDialog.setContentView(localView);
+        return localLoadingDialog;
+    }
+}

+ 19 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/DoorLightHelper.java

@@ -0,0 +1,19 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
+import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
+
+public class DoorLightHelper {
+
+    public static void handleDoorLight(TcpModel tcpModel) {
+        if (TcpAction.SideAction.CALL == tcpModel.getAction()
+            || TcpAction.SideAction.SOS_CALL == tcpModel.getAction()) {
+            //门灯红色闪烁
+            SerialPortHelper.setDoorLight(1, "200"); //红色闪烁
+        } else if (TcpAction.SideAction.ACCEPT == tcpModel.getAction()
+            || TcpAction.SideAction.CANCEL == tcpModel.getAction()
+            || TcpAction.SideAction.SOS_CANCEL == tcpModel.getAction()) {
+            SerialPortHelper.setDoorLight(1, "111"); //白色
+        }
+    }
+}

+ 189 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/HttpHelper.java

@@ -0,0 +1,189 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import static com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper.FILE_APK_NAME;
+import static com.wdkl.app.ncs.callingbed.helper.AppUpdateHelper.FILE_APK_PATH;
+
+public class HttpHelper {
+    private static OkHttpClient okHttpClient = null;
+
+    /**
+     * @param url   服务器地址
+     * @param file  所要上传的文件
+     */
+    public static void upload(String url, File file, Object tag, UploadCallback callback) {
+        if (okHttpClient == null) {
+            okHttpClient = new OkHttpClient();
+        }
+
+        RequestBody requestBody = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM)
+                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file))
+                .build();
+
+        Request request = new Request.Builder()
+                .url(url)
+                .tag(tag)
+                .post(requestBody)
+                .build();
+
+        okHttpClient.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                if (callback != null) {
+                    callback.onFail();
+                }
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+                Log.d("upload", "voice msg response: " + response.toString());
+               if( response.code()==200 && response.body() != null) {
+                   String data = response.body().string();
+                   //voice msg response: upload/file/202104102037715.mp3
+                   if (callback != null) {
+                       callback.onSuccess(data);
+                   }
+               } else {
+                   if (callback != null) {
+                       callback.onFail();
+                   }
+               }
+            }
+        });
+    }
+
+    public static void download(String url, Object tag, final DownloadListener listener) {
+        if (okHttpClient == null) {
+            okHttpClient = new OkHttpClient();
+        }
+
+        Request request = new Request.Builder()
+                .url(url)
+                .tag(tag)
+                .build();
+
+        okHttpClient.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                Log.d("download", "onFailure==" + e.toString());
+                if (listener != null) {
+                    listener.onDownloadFailed(); // 下载失败
+                }
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) {
+                Log.d("download", "response==" + response.body().contentLength());
+                InputStream is = null;
+                byte[] buf = new byte[2048];
+                int len;
+                FileOutputStream fos = null;
+                try {
+                    is = response.body().byteStream();
+                    long total = response.body().contentLength();
+                    File file = new File(isHaveExistDir(new File(FILE_APK_PATH), new File(FILE_APK_PATH + "/" + FILE_APK_NAME)), FILE_APK_NAME);
+                    fos = new FileOutputStream(file);
+                    long sum = 0;
+                    while ((len = is.read(buf)) != -1) {
+                        fos.write(buf, 0, len);
+                        sum = sum + (long) len;
+                        //int progress = (int) (sum * 1.0f / total * 100);
+                        float sp = (float) sum / (float) total;
+                        int progress = (int) (sp * 100);
+                        Log.d("download", "progress==" + progress);
+                        if (listener != null) {
+                            listener.onDownloading(progress);// 下载中
+                        }
+                    }
+                    fos.flush();
+                    if (listener != null) {
+                        listener.onDownloadSuccess(); // 下载完成
+                    }
+                } catch (Exception e) {
+                    Log.d("download", "Exception==");
+                    if (listener != null) {
+                        listener.onDownloadFailed();
+                    }
+                } finally {
+                    try {
+                        if (is != null)
+                            is.close();
+                        if (fos != null)
+                            fos.close();
+                    } catch (IOException e) {
+                        Log.d("download", "IOException==");
+                    }
+                }
+            }
+        });
+    }
+
+    public static void cancelRequestByTag(Object tag) {
+        if (okHttpClient != null && tag != null) {
+            for (Call call : okHttpClient.dispatcher().queuedCalls()) {
+                if (tag.equals(call.request().tag())) {
+                    call.cancel();
+                }
+            }
+
+            for (Call call : okHttpClient.dispatcher().runningCalls()) {
+                if (tag.equals(call.request().tag())) {
+                    call.cancel();
+                }
+            }
+        }
+    }
+
+    private static String isHaveExistDir(File downloadFile, File sonFile) throws IOException {
+        Log.d("download", "downloadFile.mkdirs()==" + downloadFile.mkdirs());
+        Log.d("download", "sonFile.mkdir()==" + sonFile.mkdir());
+        if (!downloadFile.mkdirs()) {
+            downloadFile.createNewFile();
+        }
+        deleteAPKFile(sonFile);//只要文件名相同就可以自动替换(按道理此处不需要了,但为了保险起见还是先执行删除操作)。
+        return downloadFile.getAbsolutePath();
+    }
+
+    public static boolean deleteAPKFile(File downloadFile) {
+        return downloadFile.delete();
+    }
+
+
+    public interface UploadCallback{
+        void onFail();
+        void onSuccess(String data);
+    }
+
+    public interface DownloadListener {
+        /**
+         * 下载成功
+         */
+        void onDownloadSuccess();
+
+        /**
+         * @param progress 下载进度
+         */
+        void onDownloading(int progress);
+
+        /**
+         * 下载失败
+         */
+        void onDownloadFailed();
+    }
+}

+ 83 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ImPlayDialogHelper.java

@@ -0,0 +1,83 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.Chronometer;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+
+public class ImPlayDialogHelper {
+
+    private static AlertDialog imPlayDialog;
+
+    public static void showImPlayDialog(Activity activity, String text, String time) {
+        if (imPlayDialog != null && imPlayDialog.isShowing()) {
+            return;
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.im_play_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        Button confirm = contentView.findViewById(R.id.btn_im_stop);
+        confirm.setOnClickListener(v -> {
+            MediaPlayHelper.getInstance().stopMusic();
+            dismissIMDialog();
+        });
+        TextView textView = contentView.findViewById(R.id.tv_im_play_name);
+        textView.setText(text);
+        TextView timeView = contentView.findViewById(R.id.tv_im_time);
+        timeView.setText(time);
+        Chronometer chronometer = contentView.findViewById(R.id.im_play_time);
+        chronometer.setBase(SystemClock.elapsedRealtime());
+        chronometer.start();
+
+
+        imPlayDialog = builder.create();
+        imPlayDialog.setCanceledOnTouchOutside(false);
+        imPlayDialog.setCancelable(false);
+        imPlayDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                if (chronometer != null) {
+                    chronometer.stop();
+                }
+            }
+        });
+
+        //设置dialog宽高及位置
+        try {
+            Window window = imPlayDialog.getWindow();
+            window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+            imPlayDialog.show();
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.gravity = Gravity.CENTER;
+            //lp.alpha = 0.8f;//设置透明度
+            window.setAttributes(lp);
+
+            window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismissIMDialog() {
+        if (imPlayDialog != null) {
+            imPlayDialog.dismiss();
+            imPlayDialog = null;
+        }
+    }
+}

+ 61 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/KaerStatsBarHelper.java

@@ -0,0 +1,61 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.content.Context;
+import android.content.Intent;
+
+public class KaerStatsBarHelper {
+    public static void toggleStatusBar(Context context, Boolean show) {
+//        Process process;
+//        PrintWriter printWriter;
+//        BufferedReader errorStream = null;
+//        BufferedReader successStream = null;
+//        Boolean result = false;
+//        try {
+//            process = Runtime.getRuntime().exec("su");
+//            printWriter = new PrintWriter(process.getOutputStream());
+////            printWriter.println("reboot");
+////            printWriter.println("am stopservice com.wdkl.ncs.android.component.welcome.service.APPService");
+//            printWriter.println("am broadcast -a com.kaer.action.WHETHER_SHOW_NAVIGATION --ez show_navigation_bar true");//下方虚拟按键
+////            printWriter.println("am broadcast -a com.kaer.action.OPEN_PANEL_ENABLED --ez open_panel_enabled "+(show?"true":"false"));//上面状态栏下拉控制
+////            printWriter.println("am broadcast -a com.kaer.action.WHETHER_SHOW_STATUSBAR --ez show_status_bar "+(show?"true":"false"));//上面状态栏显示
+//            printWriter.flush();
+//            printWriter.close();
+//            process.waitFor();
+//            Log.i("改变状态栏", "toggleStatusBar: ");
+//            return  true;
+//        } catch (Exception e) {
+//            if(errorStream!=null){
+//                try {
+//                    errorStream.close();
+//                } catch (IOException ioException) {
+//                    ioException.printStackTrace();
+//                }
+//            }
+//            if(successStream!=null){
+//                try {
+//                    successStream.close();
+//                } catch (IOException ioException) {
+//                    ioException.printStackTrace();
+//                }
+//            }
+//
+//            return false;
+//        }
+
+        Intent intent = new Intent();
+        intent.setAction("com.kaer.action.WHETHER_SHOW_NAVIGATION");
+        intent.putExtra("show_navigation_bar", show);
+        context.sendBroadcast(intent);
+
+        Intent intent2 = new Intent();
+        intent2.setAction("com.kaer.action.OPEN_PANEL_ENABLED");
+        intent2.putExtra("open_panel_enabled", show);
+        context.sendBroadcast(intent2);
+
+        Intent intent3 = new Intent();
+        intent3.setAction("com.kaer.action.WHETHER_SHOW_STATUSBAR");
+        intent3.putExtra("show_status_bar", show);
+        context.sendBroadcast(intent3);
+
+    }
+}

+ 145 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/LanguageSetDialogHelper.java

@@ -0,0 +1,145 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.ncs.android.lib.core.locale.LocaleMangerUtils;
+import com.wdkl.ncs.android.lib.core.locale.SettingConfigNew;
+
+
+public class LanguageSetDialogHelper {
+
+    private static AlertDialog dialog;
+    private static int selectIndex;
+
+    public static void showDialog(final Activity activity) {
+        if (dialog != null && dialog.isShowing()) {
+            return;
+        }
+
+        final int originIndex = LocaleMangerUtils.getCurrentLocaleIndex();
+        selectIndex = originIndex;
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.language_set_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        RadioButton btnYes = contentView.findViewById(R.id.rb_language_yes);
+        RadioButton btnNo = contentView.findViewById(R.id.rb_language_no);
+        final int mode = SettingConfigNew.getLanguageMode(activity);
+        if (mode == 0) {
+            btnYes.setChecked(true);
+        } else {
+            btnNo.setChecked(true);
+        }
+
+        Button buttonCancel = contentView.findViewById(R.id.cancel_button);
+        Button buttonConfirm = contentView.findViewById(R.id.confirm_button);
+        Spinner spinner = contentView.findViewById(R.id.spinner_language_select);
+
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(activity,
+                R.array.language_list, R.layout.spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(adapter);
+        spinner.setSelection(originIndex);
+        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                Log.d("languageId", "pos: " + position + ", originIndex: " + originIndex);
+                selectIndex = position;
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+
+            }
+        });
+
+        RadioGroup languageGroup = contentView.findViewById(R.id.group_language_mode);
+        languageGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(RadioGroup group, int checkedId) {
+                if (checkedId == R.id.rb_language_yes) {
+                    SettingConfigNew.setLanguageMode(activity, 0);
+                } else {
+                    SettingConfigNew.setLanguageMode(activity, 1);
+                }
+            }
+        });
+
+        buttonCancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (dialog != null) {
+                    dialog.dismiss();
+                }
+            }
+        });
+
+        buttonConfirm.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                SettingConfigNew.setLanguageId(activity, selectIndex);
+
+                if (SettingConfigNew.getLanguageMode(activity) == 1) {
+                    if (selectIndex != originIndex) {
+                        Toast.makeText(activity, "restart now...", Toast.LENGTH_LONG).show();
+                        new Handler().postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                AppUpdateHelper.restartApp(activity);
+                            }
+                        }, 3000);
+                    }
+                } else {
+                    Toast.makeText(activity, "restart now...", Toast.LENGTH_LONG).show();
+                    new Handler().postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            AppUpdateHelper.restartApp(activity);
+                        }
+                    }, 3000);
+                }
+
+                if (dialog != null) {
+                    dialog.dismiss();
+                }
+            }
+        });
+
+        dialog = builder.create();
+        //dialog.setCanceledOnTouchOutside(false);
+        //dialog.setCancelable(false);
+        dialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = dialog.getWindow();
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 242 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/MediaPlayHelper.java

@@ -0,0 +1,242 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.ncs.android.middleware.common.MessageEvent;
+
+import org.greenrobot.eventbus.EventBus;
+
+public class MediaPlayHelper {
+
+    private static MediaPlayHelper sInstance = null;
+    private MediaPlayer mediaPlayer;
+    private HandlerThread playHandlerThread;
+    private Handler playHandler;
+
+    private int mResId;
+    private String mUrl;
+    private float mVolume;
+    private boolean mLoop;
+    private boolean play;
+
+    /**
+     * 播放res资源
+     */
+    public static final int PLAY_RES = 100;
+    /**
+     * 播放url资源
+     */
+    public static final int PLAY_URL = 101;
+    /**
+     * 停止
+     */
+    public static final int STOP = 102;
+    /**
+     * 释放
+     */
+    public static final int RELEASE = 103;
+
+
+    private MediaPlayHelper() {
+        createHandlerThread();
+    }
+
+    public static MediaPlayHelper getInstance() {
+        if (sInstance == null) {
+            synchronized (MediaPlayHelper.class) {
+                if (sInstance == null) {
+                    sInstance = new MediaPlayHelper();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    private void createHandlerThread() {
+        if (playHandlerThread == null) {
+            playHandlerThread = new HandlerThread("playHandlerThread");
+            playHandlerThread.start();
+        }
+
+        if (playHandler == null) {
+            playHandler = new Handler(playHandlerThread.getLooper()) {
+                @Override
+                public void handleMessage(Message msg) {
+                    switch (msg.what) {
+                        case PLAY_RES:
+                            playResMusicNow();
+                            break;
+                        case PLAY_URL:
+                            playUrlMusicNow();
+                            break;
+                        case STOP:
+                            stopMusicNow();
+                            break;
+                        case RELEASE:
+                            releaseMediaNow();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            };
+        }
+    }
+
+    public void playResMusic(int id, float vol, boolean loop) {
+        mResId = id;
+        mVolume = vol;
+        mLoop = loop;
+        playHandler.sendEmptyMessage(PLAY_RES);
+    }
+
+    public void playUrlMusic(String url, float vol, boolean loop) {
+        mUrl = url;
+        mVolume = vol;
+        mLoop = loop;
+        playHandler.sendEmptyMessage(PLAY_URL);
+    }
+
+    public void stopMusic() {
+        playHandler.sendEmptyMessage(STOP);
+    }
+
+    public void stopMusic(boolean dismiss) {
+        playHandler.sendEmptyMessage(STOP);
+        if (dismiss) {
+            ImPlayDialogHelper.dismissIMDialog();
+        }
+    }
+
+
+    public void releaseMusic() {
+        playHandler.sendEmptyMessage(RELEASE);
+    }
+
+    //播放本地res音频资源
+    private void playResMusicNow() {
+        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
+            mediaPlayer.stop();
+        }
+        mediaPlayer = MediaPlayer.create(BaseApplication.appContext, mResId);
+        try {
+            mediaPlayer.setLooping(mLoop);
+            mediaPlayer.setVolume(mVolume, mVolume);
+            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            mediaPlayer.start();
+            play = true;
+            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                @Override
+                public void onCompletion(MediaPlayer player) {
+                    //playMusicComplete();
+                    stopMusicNow();
+                    play = false;
+                }
+            });
+            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                @Override
+                public boolean onError(MediaPlayer player, int what, int extra) {
+                    //playMusicError();
+                    stopMusicNow();
+                    play = false;
+                    return false;
+                }
+            });
+        } catch (Exception e) {
+            //playMusicError();
+            play = false;
+            e.printStackTrace();
+        }
+    }
+
+    //播放远程或本地存储音频资源
+    private void playUrlMusicNow() {
+        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
+            mediaPlayer.stop();
+        }
+        mediaPlayer = new MediaPlayer();
+        try {
+            mediaPlayer.reset();
+            mediaPlayer.setDataSource(mUrl);
+            mediaPlayer.setLooping(mLoop);
+            mediaPlayer.setVolume(mVolume, mVolume);
+            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            play = true;
+            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+                @Override
+                public void onPrepared(MediaPlayer player) {
+                    if (mediaPlayer != null) {
+                        mediaPlayer.start();
+                    }
+                }
+            });
+            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                @Override
+                public void onCompletion(MediaPlayer player) {
+                    //playMusicComplete();
+                    //stopMusicNow();
+                    play = false;
+                    EventBus.getDefault().post(new MessageEvent("im_done", Constant.EVENT_IM_PLAY_DONE));
+                }
+            });
+            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                @Override
+                public boolean onError(MediaPlayer player, int what, int extra) {
+                    //playMusicError();
+                    stopMusicNow();
+                    play = false;
+                    EventBus.getDefault().post(new MessageEvent("im_done", Constant.EVENT_IM_PLAY_DONE));
+                    return false;
+                }
+            });
+            mediaPlayer.prepareAsync();
+        } catch (Exception e) {
+            //playMusicError();
+            play = false;
+            e.printStackTrace();
+        }
+    }
+
+    private void stopMusicNow() {
+        if (mediaPlayer != null) {
+            mediaPlayer.setOnPreparedListener(null);
+            mediaPlayer.setOnCompletionListener(null);
+            try {
+                //if (mediaPlayer.isPlaying()) {
+                    mediaPlayer.stop();
+                    mediaPlayer.release();
+                //}
+            } catch (IllegalStateException e) {
+                e.printStackTrace();
+            }
+        }
+        mediaPlayer = null;
+    }
+
+    private void releaseMediaNow() {
+        if (mediaPlayer != null) {
+            mediaPlayer.setOnPreparedListener(null);
+            mediaPlayer.setOnCompletionListener(null);
+            try {
+                mediaPlayer.stop();
+                mediaPlayer.release();
+            } catch (IllegalStateException e) {
+                e.printStackTrace();
+            }
+        }
+        mediaPlayer = null;
+    }
+
+    public boolean isMediaPlaying() {
+        if (mediaPlayer != null) {
+            return mediaPlayer.isPlaying();
+        }
+        return false;
+    }
+}

+ 729 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/NetHelper.java

@@ -0,0 +1,729 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.DhcpInfo;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.RouteInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+
+
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.lib.utils.EthernetUtils;
+import com.wdkl.ncs.android.lib.utils.NetParam;
+import com.wdkl.ncs.android.middleware.common.MessageEvent;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static com.wdkl.ncs.android.middleware.common.Constant.EVENT_INTERNETPING;
+
+public class NetHelper {
+    private Context mContext;
+    private WifiManager wifiManager;
+    private ConnectivityManager connManager;
+    private static NetHelper sInstance = null;
+
+    private static Timer timerNetStatus = null;
+    private static final int SCHEDULE_TIME = 30000;
+    public static boolean NetConn = false;
+
+    /**
+     * 以太网是否ping成功
+     */
+    public static final String ETHERNETSTATUS = "ethernetStatus";
+
+    public NetHelper() {
+    }
+
+    public static NetHelper getInstance() {
+        if (sInstance == null) {
+            synchronized (NetHelper.class) {
+                if (sInstance == null) {
+                    sInstance = new NetHelper();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    public void init(Context context) {
+        mContext = context;
+        wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+        connManager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
+
+    public static void startNetCheck() {
+        if (timerNetStatus != null) {
+            timerNetStatus.purge();
+        }
+        timerNetStatus = new Timer();
+        timerNetStatus.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                NetConn = ping(getLocalElement(3), 2, null);
+
+                EventBus.getDefault().post(new MessageEvent(ETHERNETSTATUS, EVENT_INTERNETPING));//循环检测SIP,以太网ping状态
+            }
+        }, 10, SCHEDULE_TIME);
+    }
+
+    /**
+     * ping 网络
+     *
+     * @param host
+     * @param pingCount
+     * @param stringBuffer
+     * @return
+     */
+    public static boolean ping(String host, int pingCount, StringBuffer stringBuffer) {
+        String line = null;
+        Process process = null;
+        BufferedReader successReader = null;
+        String command = "ping -c " + pingCount + " " + host;
+        boolean isSuccess = false;
+        try {
+            process = Runtime.getRuntime().exec(command);
+            if (process == null) {
+                append(stringBuffer, "ping fail:process is null.");
+                return false;
+            }
+            successReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+            while ((line = successReader.readLine()) != null) {
+                append(stringBuffer, line);
+            }
+            int status = process.waitFor();
+            if (status == 0) {
+                append(stringBuffer, "exec cmd success:" + command);
+                isSuccess = true;
+            } else {
+                append(stringBuffer, "exec cmd fail.");
+                isSuccess = false;
+            }
+            append(stringBuffer, "exec finished.");
+        } catch (IOException e) {
+        } catch (InterruptedException e) {
+        } finally {
+            if (process != null) {
+                process.destroy();
+            }
+            if (successReader != null) {
+                try {
+                    successReader.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+
+        return isSuccess;
+    }
+
+    private static void append(StringBuffer stringBuffer, String text) {
+        if (stringBuffer != null) {
+            stringBuffer.append(text + "\n");
+        }
+    }
+
+    /**
+     * 获取网关  Waderson
+     * <p>
+     * 1 WIFI情况下获取网关 2 有线网络下的DHCP模式连接 3 有线网络其他连接方式:比如静态ip、pppoe拨号、ipoe拨号等
+     */
+    public static String getLocalElement(int type) {
+        String e = "";
+        if (1 == type) {
+            //e = getLocalElementByWifi();
+        } else if (2 == type) {
+            e = getLocalElementByDhcp();
+        } else if (3 == type) {
+            e = getLocalElementByIp();
+        }
+        if (!TextUtils.isEmpty(e) && e.length() >= 11 && e.length() <= 15) {
+            return e;
+        } else {
+            return "192.168.101.1";
+        }
+    }
+    /**
+     * 设置动态网络
+     */
+    public void setDynamicNetwork(boolean istype) {
+        // 检查当前网络连接状态
+        NetworkCapabilities networkCapabilities = connManager.getNetworkCapabilities(connManager.getActiveNetwork());
+        if (networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+            // 连接到互联网,进行相关操作
+            // ...
+            if (istype){
+                // 设置动态网络配置(DHCP)
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                    Network network = connManager.getActiveNetwork();
+                    connManager.bindProcessToNetwork(network);
+                }
+            }else {
+                // 设置静态网络配置
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                    // 对于Android Lollipop及以上版本,您可以使用WifiManager来为Wi-Fi网络设置静态IP配置
+                    if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                        WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+                        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+                        if (wifiInfo != null) {
+                            DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
+                            if (dhcpInfo != null) {
+                                int ipAddress = dhcpInfo.ipAddress;
+                                int gateway = dhcpInfo.gateway;
+                                int netmask = dhcpInfo.netmask;
+                                int dns1 = dhcpInfo.dns1;
+                                int dns2 = dhcpInfo.dns2;
+
+
+                            }
+                        }
+                    }
+                }
+            }
+
+        } else {
+            // 未连接到互联网,根据情况进行处理
+            // ...
+        }
+    }
+
+
+    /**
+     * 获取网关  Waderson
+     * <p>
+     * 1 WIFI情况下获取网关 2 有线网络下的DHCP模式连接 3 有线网络其他连接方式:比如静态ip、pppoe拨号、ipoe拨号等
+     */
+    public String gateway() {
+        try {
+            String e = "";
+            //先判断是否有线
+            Network network = connManager.getActiveNetwork();
+            NetworkCapabilities networkCapabilities = connManager.getNetworkCapabilities(network);
+            if (networkCapabilities != null) {
+                if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                    // Wi-Fi 网络连接
+                    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+                    if (wifiInfo != null) {
+
+                        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
+                        e = Formatter.formatIpAddress(dhcpInfo.gateway);
+
+                    } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
+                        // 有线网络连接
+                        e = getLocalElementByDhcp();
+
+                    } else {
+                        // 其他类型的网络连接
+                        e = getLocalElementByIp();
+                    }
+                }
+            }
+            if (!TextUtils.isEmpty(e) && e.length() >= 11 && e.length() <= 15) {
+                return e;
+            } else {
+                return "192.168.101.1";
+            }
+        } catch (Exception exception) {
+            exception.printStackTrace();
+        }
+        return null;
+    }
+    /**
+     * 获取掩码 Waderson
+     * <p>
+     * 1 WIFI情况下获取网关 2 有线网络下的DHCP模式连接 3 有线网络其他连接方式:比如静态ip、pppoe拨号、ipoe拨号等
+     */
+    public String getmask() {
+        try {
+            String e = "";
+            //先判断是否有线
+            Network network = connManager.getActiveNetwork();
+            NetworkCapabilities networkCapabilities = connManager.getNetworkCapabilities(network);
+            if (networkCapabilities != null) {
+                if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                    // Wi-Fi 网络连接
+                    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+                    if (wifiInfo != null) {
+                        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
+                        e = Formatter.formatIpAddress(dhcpInfo.netmask);
+                    } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
+                        // 有线网络连接
+                        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+                        while (networkInterfaces.hasMoreElements()) {
+                            NetworkInterface networkInterface = networkInterfaces.nextElement();
+                            if (networkInterface.isUp() && !networkInterface.isLoopback()) {
+                                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
+                                while (inetAddresses.hasMoreElements()) {
+                                    InetAddress inetAddress = inetAddresses.nextElement();
+                                    if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
+                                        e =getSubnetMaskFromPrefixLength(networkInterface.getInterfaceAddresses().get(0).getNetworkPrefixLength());
+                                    }
+                                }
+                            }
+                        }
+
+
+                    }
+                }
+            }
+            if (!TextUtils.isEmpty(e)) {
+                return e;
+            } else {
+                return "0.0.0.0";
+            }
+        } catch (Exception exception) {
+            exception.printStackTrace();
+        }
+        return null;
+    }
+    // 根据前缀长度获取子网掩码
+    private String getSubnetMaskFromPrefixLength(int prefixLength) {
+        try {
+            int maskBits = 0xffffffff << (32 - prefixLength);
+            byte[] maskBytes = new byte[]{
+                    (byte) (maskBits >>> 24),
+                    (byte) (maskBits >> 16 & 0xff),
+                    (byte) (maskBits >> 8 & 0xff),
+                    (byte) (maskBits & 0xff)
+            };
+            InetAddress inetAddress = InetAddress.getByAddress(maskBytes);
+            return inetAddress.getHostAddress();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static NetParam getNetInfo(Context context) {
+        try {
+            int type = EthernetUtils.getEthUseDhcpOrStaticIp(context);
+            if ( type == 1) {
+                //静态ip
+                return EthernetUtils.getEthInfoFromStaticIp(context);
+            } else if (type == 2){
+                //动态IP
+                return EthernetUtils.getEthInfoFromDhcp(context);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+
+    /**
+     * 有线网络下的DHCP模式连接
+     */
+    public static String getLocalElementByDhcp() {
+        BufferedReader bufferedReader = null;
+        String str2 = "";
+        String str3 = "getprop dhcp.eth0.gateway";
+        Process exec;
+        BufferedReader bufferedReader2 = null;
+        try {
+            exec = Runtime.getRuntime().exec(str3);
+            try {
+                bufferedReader2 = new BufferedReader(new InputStreamReader(exec.getInputStream()));
+            } catch (Throwable th3) {
+                if (bufferedReader != null) {
+                    bufferedReader.close();
+                }
+                if (exec != null) {
+                    exec.exitValue();
+                }
+            }
+            try {
+                str3 = bufferedReader2.readLine();
+                if (str3 != null) {
+                    TextUtils.isEmpty(str3);
+                }
+                try {
+                    bufferedReader2.close();
+                } catch (IOException iOException222) {
+                    iOException222.printStackTrace();
+                }
+                if (exec != null) {
+                    try {
+                        exec.exitValue();
+                    } catch (Exception e5) {
+                    }
+                }
+            } catch (IOException e6) {
+                str3 = str2;
+                if (bufferedReader2 != null) {
+                    bufferedReader2.close();
+                }
+                if (exec != null) {
+                    exec.exitValue();
+                }
+                return str3;
+            }
+        } catch (IOException e62) {
+            bufferedReader2 = null;
+            exec = null;
+            str3 = str2;
+            if (bufferedReader2 != null) {
+                try {
+                    bufferedReader2.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (exec != null) {
+                exec.exitValue();
+            }
+            return str3;
+        } catch (Throwable th4) {
+            exec = null;
+            if (bufferedReader != null) {
+                try {
+                    bufferedReader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (exec != null) {
+                exec.exitValue();
+            }
+        }
+        return str3;
+    }
+
+    /**
+     * 有线网络其他连接方式:比如静态ip、pppoe拨号、ipoe拨号等
+     */
+    public static String getLocalElementByIp() {
+        BufferedReader bufferedReader = null;
+        String result = "";
+        String str2 = "";
+        String str3 = "ip route list table 0";
+        Process exec;
+        BufferedReader bufferedReader2 = null;
+        try {
+            exec = Runtime.getRuntime().exec(str3);
+            try {
+                bufferedReader2 = new BufferedReader(new InputStreamReader(exec.getInputStream()));
+            } catch (Throwable th3) {
+                if (bufferedReader != null) {
+                    bufferedReader.close();
+                }
+                if (exec != null) {
+                    exec.exitValue();
+                }
+            }
+            try {
+                str2 = bufferedReader2.readLine();
+                if (str2 != null) {
+                    str2 = str2.trim();
+                    String[] strings = str2.split("\\s+");
+                    if (strings.length > 3) {
+                        result = strings[2];
+                    }
+                }
+                try {
+                    bufferedReader2.close();
+                } catch (IOException iOException222) {
+                    iOException222.printStackTrace();
+                }
+                if (exec != null) {
+                    try {
+                        exec.exitValue();
+                    } catch (Exception e5) {
+                    }
+                }
+            } catch (IOException e6) {
+                if (bufferedReader2 != null) {
+                    bufferedReader2.close();
+                }
+                if (exec != null) {
+                    exec.exitValue();
+                }
+                return result;
+            }
+        } catch (IOException e62) {
+            bufferedReader2 = null;
+            exec = null;
+            if (bufferedReader2 != null) {
+                try {
+                    bufferedReader2.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (exec != null) {
+                exec.exitValue();
+            }
+            return result;
+        } catch (Throwable th4) {
+            exec = null;
+            if (bufferedReader != null) {
+                try {
+                    bufferedReader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (exec != null) {
+                exec.exitValue();
+            }
+        }
+        return result;
+    }
+
+    //获取本地ip地址
+    public String getLocalIP() {
+        try {
+            for (Enumeration<NetworkInterface> enNetI = NetworkInterface.getNetworkInterfaces(); enNetI.hasMoreElements(); ) {
+                NetworkInterface netI = enNetI.nextElement();
+                for (Enumeration<InetAddress> enumIpAddr = netI.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
+                    InetAddress inetAddress = enumIpAddr.nextElement();
+                    if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
+                        return inetAddress.getHostAddress();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 得到MAC
+     *
+     * @return String
+     */
+    public String getMacAddress() {
+        String mac = "";
+        try {
+            mac = getLocalMacAddressFromIp();
+            if (TextUtils.isEmpty(mac)) {
+                mac = getNetworkMac();
+            }
+            if (TextUtils.isEmpty(mac)) {
+                mac = tryGetWifiMac();
+            }
+        } catch (Exception e) {
+        }
+        return mac;
+    }
+
+    /**
+     * 通过WiFiManager获取mac地址
+     * 这个方法Android 7.0是获取不到的,返回的是null,其实是返回“02:00:00:00:00:00”
+     *
+     * @return
+     */
+    public String tryGetWifiMac() {
+        String mac;
+        WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        WifiInfo wi = wm.getConnectionInfo();
+        if (wi == null || wi.getMacAddress() == null) {
+            mac = null;
+        }
+        if ("02:00:00:00:00:00".equals(wi.getMacAddress().trim())) {
+            mac = null;
+        } else {
+            mac = wi.getMacAddress().trim();
+        }
+        return mac;
+    }
+
+    /**
+     * 通过网络接口获取
+     *
+     * @return
+     */
+    public static String getNetworkMac() {
+        try {
+            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
+            for (NetworkInterface nif : all) {
+                // if (!nif.getName().equalsIgnoreCase("wlan0") && !nif.getName().equalsIgnoreCase("eth0") && !nif.getName().equalsIgnoreCase("eth1"))
+                if (!nif.getName().equalsIgnoreCase("eth0") && !nif.getName().equalsIgnoreCase("eth1") && !nif.getName().equalsIgnoreCase("eth2"))
+                    continue;
+                byte[] macBytes = nif.getHardwareAddress();
+                if (macBytes == null) {
+                    return null;
+                }
+                StringBuilder res1 = new StringBuilder();
+                for (byte b : macBytes) {
+                    res1.append(String.format("%02X:", b));
+                }
+                if (res1.length() > 0) {
+                    res1.deleteCharAt(res1.length() - 1);
+                }
+                return res1.toString();
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 根据IP地址获取MAC地址
+     *
+     * @return
+     */
+    @SuppressLint("NewApi")
+    public static String getLocalMacAddressFromIp() {
+        String strMacAddr = null;
+        try {
+            // 获得IpD地址
+            InetAddress ip = getLocalInetAddress();
+            byte[] b = NetworkInterface.getByInetAddress(ip)
+                    .getHardwareAddress();
+            StringBuffer buffer = new StringBuffer();
+            for (int i = 0; i < b.length; i++) {
+                if (i != 0) {
+                    buffer.append(':');
+                }
+                String str = Integer.toHexString(b[i] & 0xFF);
+                buffer.append(str.length() == 1 ? 0 + str : str);
+            }
+            strMacAddr = buffer.toString().toUpperCase();
+
+        } catch (Exception e) {
+
+        }
+
+        return strMacAddr;
+    }
+
+    /**
+     * 获取移动设备本地IP
+     *
+     * @return
+     */
+    public static InetAddress getLocalInetAddress() {
+        InetAddress ip = null;
+        try {
+            // 列举
+            Enumeration<NetworkInterface> en_netInterface = NetworkInterface
+                    .getNetworkInterfaces();
+            while (en_netInterface.hasMoreElements()) {// 是否还有元素
+                NetworkInterface ni = (NetworkInterface) en_netInterface
+                        .nextElement();// 得到下一个元素
+                Enumeration<InetAddress> en_ip = ni.getInetAddresses();// 得到一个ip地址的列举
+                while (en_ip.hasMoreElements()) {
+                    ip = en_ip.nextElement();
+                    if (!ip.isLoopbackAddress()
+                            && ip.getHostAddress().indexOf(":") == -1)
+                        break;
+                    else
+                        ip = null;
+                }
+
+                if (ip != null) {
+                    break;
+                }
+            }
+        } catch (SocketException e) {
+
+            e.printStackTrace();
+        }
+        return ip;
+    }
+
+    public String getIMEI() {
+        //获取序列号
+        String serial = null;
+        try {
+            serial = android.os.Build.SERIAL;
+            if (serial.equalsIgnoreCase("unknown")||serial.equalsIgnoreCase("0123456789abcdef")) {
+                final TelephonyManager mTelephony = (TelephonyManager) BaseApplication.appContext.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                    if (BaseApplication.appContext.getApplicationContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
+                        serial = null;
+                    }
+                }
+                assert mTelephony != null;
+
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                    serial = mTelephony.getImei();
+                } else {
+                    serial = mTelephony.getDeviceId();
+                }
+
+                if (TextUtils.isEmpty(serial)) {
+                    serial = Settings.Secure.getString(BaseApplication.appContext.getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
+                }
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return serial;
+    }
+
+    public static boolean isBTConnected() {
+        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (btAdapter != null) {
+            return btAdapter.getState() == BluetoothAdapter.STATE_ON;
+        }
+
+        return false;
+    }
+
+    public int getNetworkType() {
+        if (connManager != null && connManager.getActiveNetworkInfo() != null) {
+            return connManager.getActiveNetworkInfo().getType();
+        }
+
+        return -1;
+    }
+
+    public boolean networkAvailable() {
+        if (connManager != null && connManager.getActiveNetworkInfo() != null) {
+            return connManager.getActiveNetworkInfo().isConnected();
+        }
+
+        return false;
+    }
+
+    public static String getPhoneNumber(){
+        try {
+            TelephonyManager tm = (TelephonyManager) BaseApplication.appContext.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+            @SuppressLint("MissingPermission") String te1 = tm.getLine1Number();//获取本机号码
+            return te1;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return "";
+    }
+}

+ 128 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/PasswordDialogHelper.java

@@ -0,0 +1,128 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.GridView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.adapter.NumAdapter;
+import com.wdkl.ncs.android.middleware.utils.StringUtil;
+
+
+public class PasswordDialogHelper {
+
+    private static AlertDialog dialog;
+    private static String pwd = "";
+
+    public static void showPasswordDialog(final Activity activity, final MyListener listener) {
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.password_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        final String[] numbers = {"1","2","3","4","5","6","7","8","9"};
+        final TextView password = contentView.findViewById(R.id.tv_psw_view);
+        final LinearLayout llPwd = contentView.findViewById(R.id.ll_password);
+        final LinearLayout llServer = contentView.findViewById(R.id.ll_server_config);
+        GridView gridView = contentView.findViewById(R.id.grid_psw);
+        NumAdapter adapter = new NumAdapter(numbers, activity);
+        gridView.setAdapter(adapter);
+        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                if (pwd.length() <= 2) {
+                    pwd = pwd + numbers[position];
+                    password.setText(pwd);
+                }
+            }
+        });
+
+        TextView delete = contentView.findViewById(R.id.btn_delete);
+        TextView cancel = contentView.findViewById(R.id.btn_cancel);
+        TextView confirm = contentView.findViewById(R.id.btn_confirm);
+        delete.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d("pwd", "delete password len: " + pwd.length() + "--" + pwd);
+                if (pwd.length() > 1) {
+                    pwd = pwd.substring(0, pwd.length()-1);
+                    password.setText(pwd);
+                } else {
+                    pwd = "";
+                    password.setText(pwd);
+                    password.setHint(R.string.input_password);
+                }
+            }
+        });
+
+        cancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissCallDialog();
+            }
+        });
+
+        confirm.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if ("888".equals(pwd)) {
+                    if (listener != null) {
+                        listener.onConfirm();
+                        dismissCallDialog();
+                    }
+                } else {
+                    Toast.makeText(activity, StringUtil.getResString(R.string.invalid_password), Toast.LENGTH_SHORT).show();
+                }
+            }
+        });
+
+
+
+
+        dialog = builder.create();
+        dialog.setCanceledOnTouchOutside(false);
+        dialog.setCancelable(false);
+        dialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = dialog.getWindow();
+            window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 400;
+            lp.height = 480;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+
+            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismissCallDialog() {
+        pwd = "";
+        if (dialog != null && dialog.isShowing()) {
+            dialog.dismiss();
+        }
+    }
+
+    public interface MyListener{
+        void onConfirm();
+    }
+}

+ 126 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/RecordHelper.java

@@ -0,0 +1,126 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.media.MediaRecorder;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+public class RecordHelper {
+    private static final String VOICE_MSG_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/VoiceMsg";
+    private String audiofilePath;
+    private MediaRecorder mediaRecorder;
+    private static RecordHelper sInstance = null;
+    private boolean recording = false;
+
+    private final static Object lock = new Object();
+
+    public RecordHelper() {
+    }
+
+    public static RecordHelper getInstance() {
+        if (sInstance == null) {
+            synchronized (RecordHelper.class) {
+                if (sInstance == null) {
+                    sInstance = new RecordHelper();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    public void init() {
+        //创建音频文件路径
+        File file = new File(VOICE_MSG_FILE_PATH);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+    }
+
+    public void startRecord() {
+        audiofilePath = VOICE_MSG_FILE_PATH + "/" + System.currentTimeMillis() + "_voice.mp3";
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lock) {
+                    try {
+                        mediaRecorder = new MediaRecorder();
+                        mediaRecorder.setOutputFile(audiofilePath);
+                        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置MediaRecorder的音频源为麦克风
+                        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 设置MediaRecorder录制的音频格式
+                        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);// 设置MediaRecorder录制音频的编码为amr
+                        mediaRecorder.prepare();
+                        mediaRecorder.start();
+                        recording = true;
+                    } catch (IOException e) {
+                        Log.i("error", "call startAmr(File mRecAudioFile) failed!" + e.getMessage());
+                    }
+                }
+            }
+        }).start();
+    }
+
+    public void stopRecord() {
+        synchronized (lock) {
+            try {
+                mediaRecorder.stop();
+                mediaRecorder.release();
+                mediaRecorder = null;
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                recording = false;
+            }
+        }
+    }
+
+    public void recordTestStart() {
+        audiofilePath = VOICE_MSG_FILE_PATH + "/" + System.currentTimeMillis() + "_voice.mp3";
+        synchronized (lock) {
+            try {
+                mediaRecorder = new MediaRecorder();
+                mediaRecorder.setOutputFile(audiofilePath);
+                mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置MediaRecorder的音频源为麦克风
+                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 设置MediaRecorder录制的音频格式
+                mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);// 设置MediaRecorder录制音频的编码为amr
+                mediaRecorder.prepare();
+                mediaRecorder.start();
+                recording = true;
+            } catch (IOException e) {
+                Log.i("error", "call startAmr(File mRecAudioFile) failed!" + e.getMessage());
+            }
+        }
+    }
+
+    public void recordTestStop() {
+        synchronized (lock) {
+            try {
+                mediaRecorder.stop();
+                mediaRecorder.release();
+                mediaRecorder = null;
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                recording = false;
+            }
+        }
+    }
+
+    public void deleteAudioFile(String path) {
+        synchronized (lock) {
+            File file = new File(path);
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+
+    public void deleteAudioFile() {
+        deleteAudioFile(audiofilePath);
+    }
+
+    public String getAudiofilePath() {
+        return audiofilePath;
+    }
+}

+ 58 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SOSHelper.java

@@ -0,0 +1,58 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.ncs.android.middleware.tcp.TcpClient;
+import com.wdkl.ncs.android.middleware.tcp.channel.OtherUtil;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
+
+
+/*
+ * 紧急按钮辅助类
+ */
+public class SOSHelper {
+
+    private final static Handler handler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            sosStop();
+        }
+    };
+
+    public static void sosStart() {
+        SerialPortHelper.setSosLight("2");
+        //如果该床位绑定了紧急按钮则直接通过紧急按钮设备id发送sos请求
+        if (Constant.EMERGENCY_ID != -1) {
+            TcpModel tcpModel = OtherUtil.SOSCall(Constant.EMERGENCY_ID);
+            TcpClient.getInstance().sendMsg(tcpModel.toJson());
+        } else {
+            TcpModel tcpModel = OtherUtil.RoomSOSCall(Constant.DEVICE_ID);
+            TcpClient.getInstance().sendMsg(tcpModel.toJson());
+        }
+
+        //60s之后紧急按钮灯自动复位
+        handler.removeCallbacksAndMessages(null);
+        handler.sendEmptyMessageDelayed(110, 120000);
+    }
+    public static void sostime(Object data) {
+        if (Constant.EMERGENCY_ID != -1) {
+            TcpModel tcpModel = OtherUtil.SosTime(Constant.EMERGENCY_ID,data);
+            TcpClient.getInstance().sendMsg(tcpModel.toJson());
+        } else {
+            TcpModel tcpModel = OtherUtil.SosTime(Constant.DEVICE_ID,data);
+            TcpClient.getInstance().sendMsg(tcpModel.toJson());
+        }
+
+    }
+    public static void sosStop() {
+        handler.removeCallbacksAndMessages(null);
+        if (Constant.day_state == 1) {
+            SerialPortHelper.setSosLight("1");
+        } else {
+            SerialPortHelper.setSosLight("0");
+        }
+    }
+}

+ 81 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ScreenManagerUtil.kt

@@ -0,0 +1,81 @@
+package com.wdkl.app.ncs.callingbed.helper
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import android.util.Log
+
+class ScreenManagerUtil {
+
+
+    /**
+     * @return 0--255
+     */
+    fun getScreenBrightness(context: Context): Int {
+        var screenBrightness = 150
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (!Settings.System.canWrite(context)) {
+                val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
+                intent.data = Uri.parse("package:" + context.packageName)
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                context.startActivity(intent)
+            } else {
+                //有了权限,具体的动作
+                try {
+                    screenBrightness = Settings.System.getInt(context.contentResolver,
+                            Settings.System.SCREEN_BRIGHTNESS)
+                } catch (e: Settings.SettingNotFoundException) {
+                    e.printStackTrace()
+                }
+
+            }
+        } else {
+            try {
+                screenBrightness = Settings.System.getInt(context.contentResolver,
+                        Settings.System.SCREEN_BRIGHTNESS)
+            } catch (e: Settings.SettingNotFoundException) {
+                e.printStackTrace()
+            }
+
+        }
+
+        return screenBrightness
+    }
+
+
+    /**
+     * 保存当前的屏幕亮度值,并使之生效
+     *
+     * @param paramInt 0-255
+     */
+    fun setScreenBrightness(context: Context, paramInt: Int) {
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (!Settings.System.canWrite(context)) {
+                val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
+                intent.data = Uri.parse("package:" + context.packageName)
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                context.startActivity(intent)
+            } else {
+                //有了权限,具体的动作
+                Settings.System.putInt(context.contentResolver,
+                        Settings.System.SCREEN_BRIGHTNESS, paramInt)
+                val uri = Settings.System
+                        .getUriFor("screen_brightness")
+                Log.w("当前亮度", "当前亮度======" + getScreenBrightness(context))
+                context.contentResolver.notifyChange(uri, null)
+            }
+        } else {
+            Settings.System.putInt(context.contentResolver,
+                    Settings.System.SCREEN_BRIGHTNESS, paramInt)
+            val uri = Settings.System
+                    .getUriFor("screen_brightness")
+            Log.w("当前亮度", "当前亮度======" + getScreenBrightness(context))
+            context.contentResolver.notifyChange(uri, null)
+        }
+
+    }
+}

+ 62 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SerialPortHelper.java

@@ -0,0 +1,62 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.os.Build;
+
+import serialporttest.utils.SerialPortUtil;
+
+public class SerialPortHelper {
+
+    //MIC设置
+    public static void setHandsMIC(boolean isHandsMIC) {
+        if (Build.MODEL.equals("rk3128")) {
+            if (isHandsMIC) {
+                //打开手柄mic
+                SerialPortUtil.getInstance().sendCommand(SerialPortUtil.MIC, "0", "F");
+            } else {
+                //打开面板mic
+                SerialPortUtil.getInstance().sendCommand(SerialPortUtil.MIC, "1", "F");
+            }
+        }
+    }
+
+    /*
+     * 呼叫和通话状态
+     * data: 0 -- 正常,  1 -- 呼叫中, 2 -- 通话中
+     */
+    public static void setCallStatus(String data) {
+            SerialPortUtil.getInstance().sendCommand(SerialPortUtil.CALL_STATUS, data, "F");
+
+    }
+
+    /**
+     * 设置卫生间紧急按钮灯状态: 0关闭1打开2闪烁
+     */
+    public static void setSosLight(String state) {
+        //if (Build.MODEL.equals("rk3128")) {
+            SerialPortUtil.getInstance().sendCommand(SerialPortUtil.ULED, state, "F");
+        //}
+    }
+
+    /**
+     * 门灯控制开关
+     *
+     * @param data  0  表示灯灭   1  表示灯亮
+     * @param color 0 表示灯灭  非0表示灯的颜色
+     */
+    public static void setDoorLight(int data, String color) {
+        String command;
+        if (data == 0 || color == null) {
+            command = "000";
+        } else {
+            command = color;
+        }
+        SerialPortUtil.getInstance().sendCommand(SerialPortUtil.DOORLIGHT, command, "F");
+    }
+
+    //重置设备
+    public static void resetDevice() {
+        if (Build.MODEL.equals("rk3128")) {
+            SerialPortUtil.getInstance().sendCommand(SerialPortUtil.NET_STATUS, "1", "F");
+        }
+    }
+}

+ 159 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/ServerConfigDialogHelper.java

@@ -0,0 +1,159 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.GridView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.adapter.NumAdapter;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.lib.utils.ExtendMethodsKt;
+import com.wdkl.ncs.android.middleware.utils.CommonUtils;
+
+
+public class ServerConfigDialogHelper {
+
+    private static AlertDialog callDialog;
+    private static String pwd = "";
+
+    public static void showPasswordDialog(final Activity activity) {
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.server_config_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        final String[] numbers = {"1","2","3","4","5","6","7","8","9"};
+        final TextView password = contentView.findViewById(R.id.tv_psw_view);
+        final LinearLayout llPwd = contentView.findViewById(R.id.ll_password);
+        final LinearLayout llServer = contentView.findViewById(R.id.ll_server_config);
+        GridView gridView = contentView.findViewById(R.id.grid_psw);
+        NumAdapter adapter = new NumAdapter(numbers, activity);
+        gridView.setAdapter(adapter);
+        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                if (pwd.length() <= 2) {
+                    pwd = pwd + numbers[position];
+                    password.setText(pwd);
+                }
+                Log.d("serverIp", "input password len: " + pwd.length() + "--" + pwd);
+            }
+        });
+
+        TextView delete = contentView.findViewById(R.id.btn_delete);
+        TextView cancel = contentView.findViewById(R.id.btn_cancel);
+        TextView confirm = contentView.findViewById(R.id.btn_confirm);
+        delete.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d("serverIp", "delete password len: " + pwd.length() + "--" + pwd);
+                if (pwd.length() > 1) {
+                    pwd = pwd.substring(0, pwd.length()-1);
+                    password.setText(pwd);
+                } else {
+                    pwd = "";
+                    password.setText(pwd);
+                    password.setHint(R.string.input_password);
+                }
+            }
+        });
+
+        cancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissCallDialog();
+            }
+        });
+
+        confirm.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if ("666".equals(pwd)) {
+                    llPwd.setVisibility(View.GONE);
+                    llServer.setVisibility(View.VISIBLE);
+                } else {
+                    Toast.makeText(activity, R.string.invalid_password, Toast.LENGTH_SHORT).show();
+                }
+            }
+        });
+
+        final EditText editUrl = contentView.findViewById(R.id.edit_url);
+        final EditText editPort = contentView.findViewById(R.id.edit_port);
+        final EditText editSipUrl = contentView.findViewById(R.id.edit_sip_url);
+        final EditText editSipPort = contentView.findViewById(R.id.edit_sip_port);
+        TextView saveConfig = contentView.findViewById(R.id.btn_save_config);
+        TextView cancelConfig = contentView.findViewById(R.id.btn_cancel_config);
+        editUrl.setText(CommonUtils.getUrl(BaseApplication.appContext));
+        editPort.setText(CommonUtils.getUrlPort(BaseApplication.appContext));
+        //editSipUrl.setText(CommonUtils.getSipUrl(BaseApplication.appContext));
+        //editSipPort.setText(CommonUtils.getSipPort(BaseApplication.appContext));
+        saveConfig.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                String url = editUrl.getText().toString();
+                String port = editPort.getText().toString();
+                if (TextUtils.isEmpty(url) || TextUtils.isEmpty(port)) {
+                    ExtendMethodsKt.showMessage(R.string.input_empty);
+                } else {
+                    //保存配置
+                    CommonUtils.setUrl(BaseApplication.appContext, editUrl.getText().toString());
+                    CommonUtils.setUrlPort(BaseApplication.appContext, editPort.getText().toString());
+                    //CommonUtils.setSipUrl(BaseApplication.appContext, editSipUrl.getText().toString());
+                    //CommonUtils.setSipPort(BaseApplication.appContext, editSipPort.getText().toString());
+                    dismissCallDialog();
+                }
+            }
+        });
+        cancelConfig.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissCallDialog();
+            }
+        });
+
+
+        callDialog = builder.create();
+        callDialog.setCanceledOnTouchOutside(false);
+        callDialog.setCancelable(false);
+        callDialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = callDialog.getWindow();
+            window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 400;
+            lp.height = 480;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+
+            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismissCallDialog() {
+        pwd = "";
+        if (callDialog != null && callDialog.isShowing()) {
+            callDialog.dismiss();
+        }
+    }
+}

+ 85 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SoundPoolManager.java

@@ -0,0 +1,85 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.os.Build;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+
+import java.util.HashMap;
+
+public class SoundPoolManager {
+
+    private static SoundPoolManager instance;
+    private SoundPool soundPool;
+    private HashMap<Integer, Integer> soundID = new HashMap<>();
+    private boolean isLoaded = false;
+    private boolean inited = false;
+
+    public static SoundPoolManager getInstance() {
+        if (instance == null) {
+            instance = new SoundPoolManager();
+        }
+        return instance;
+    }
+
+    public void init() {
+        if (inited) {
+            return;
+        }
+
+        if(Build.VERSION.SDK_INT > 21){
+            SoundPool.Builder builder = new SoundPool.Builder();
+            //传入音频数量
+            builder.setMaxStreams(6);
+            //AudioAttributes是一个封装音频各种属性的方法
+            AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();
+            //设置音频流的合适的属性
+            attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);//STREAM_MUSIC
+            //加载一个AudioAttributes
+            builder.setAudioAttributes(attrBuilder.build());
+            soundPool = builder.build();
+        }else{
+            soundPool = new SoundPool(6, AudioManager.STREAM_MUSIC, 0);
+        }
+
+        //来电
+        soundID.put(1, soundPool.load(BaseApplication.appContext, R.raw.incoming_call, 1));
+        //去电
+        soundID.put(2, soundPool.load(BaseApplication.appContext, R.raw.outgoing_call, 1));
+        //测试
+        soundID.put(3, soundPool.load(BaseApplication.appContext, R.raw.mic_test, 1));
+        soundID.put(4, soundPool.load(BaseApplication.appContext, R.raw.reinforce_notify,  1));
+        soundID.put(5, soundPool.load(BaseApplication.appContext, R.raw.test_start, 1));
+        soundID.put(6, soundPool.load(BaseApplication.appContext, R.raw.ding, 1));
+        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
+            @Override
+            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+                isLoaded = true;
+                inited = true;
+            }
+        });
+    }
+
+    public int playSound(int index, float leftVol, float rightVol, int loop) {
+        try {
+            if (isLoaded) {
+                return soundPool.play(soundID.get(index), leftVol, rightVol, 1, loop, 1);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return -1;
+    }
+
+    public void stopPlaySound(int streamId) {
+        soundPool.stop(streamId);
+    }
+
+    public void release() {
+        soundPool.release();
+    }
+}

+ 197 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/SpeechUtil.java

@@ -0,0 +1,197 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.content.Context;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.UtteranceProgressListener;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class SpeechUtil {
+    private static final String TAG = "SpeechUtil";
+
+    private TextToSpeech textToSpeech;
+    private static SpeechUtil speech;
+    private int speakIndex = 0;
+    private int loopCount = 1;
+    private boolean isStop = true;
+    public volatile static ArrayList<String> speechTextList = new ArrayList<>();
+    private Thread speechThread;
+    private boolean isSpeechLoop = true;
+    private String speakSpeech;
+    private final Object lockObject = new Object();
+
+    public static SpeechUtil getInstance() {
+        if (speech == null) {
+            synchronized (SpeechUtil.class) {
+                if (speech == null) {
+                    speech = new SpeechUtil();
+                }
+            }
+        }
+        return speech;
+    }
+
+    public void init(Context context) {
+        textToSpeech = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
+            @Override
+            public void onInit(int status) {
+                if (status == TextToSpeech.SUCCESS) {
+                    int supported = textToSpeech.setLanguage(Locale.CHINESE);
+                    if ((supported != TextToSpeech.LANG_AVAILABLE) && (supported != TextToSpeech.LANG_COUNTRY_AVAILABLE)) {
+                        Constant.TTSSTATE=1;
+                        Log.d(TAG, "onInit: 当前不支持中文");
+                    } else {
+                        Constant.TTSSTATE=2;
+                        Log.d(TAG, "onInit: 支持中文");
+                    }
+                    Log.d(TAG, "onInit: TTS引擎初始化成功");
+                } else {
+                    Constant.TTSSTATE=0;
+                    Log.d(TAG, "onInit: TTS引擎初始化失败");
+                }
+            }
+
+        }, "com.iflytek.speechcloud");
+        textToSpeech.setSpeechRate(0.5f);
+    }
+
+    public void newSpeech(String text, boolean emergency) {
+        synchronized (lockObject) {
+            if (Constant.TTSSTATE.equals(2)) {
+                if (emergency) {
+                    speechTextList.add(0, text);
+                } else {
+                    speechTextList.add(text);
+                }
+                startSpeechThread();
+            }
+        }
+    }
+
+    public synchronized void speak(final String text) {
+        if (textToSpeech == null) {
+            return;
+        }
+
+        isStop = false;
+        Integer speakStatus = textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, "uniqueId");
+        if(speakStatus.equals(-1)){
+            SpeechUtil.getInstance().init(BaseApplication.appContext);
+            SpeechUtil.getInstance().startSpeechThread();
+            textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, "uniqueId");
+        }
+        textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
+            @Override
+            public void onStart(String utteranceId) {
+                //LogUtil.d(TAG, "speak onStart..." + utteranceId);
+            }
+
+            @Override
+            public void onDone(String utteranceId) {
+                speakIndex++;
+                //LogUtil.d(TAG, "speak onDone...index: " + speakIndex + ", loop: " + loopCount);
+                if (speakIndex < loopCount) {
+                    //循环播报
+                    speak(text);
+                } else {
+                    //语音播报完毕
+                    speakIndex = 0;
+                    isStop = true;
+                }
+            }
+
+            @Override
+            public void onError(String utteranceId) {
+                isStop = true;
+                Log.d(TAG, "speak onError..." + utteranceId);
+            }
+        });
+    }
+
+    public void stopSpeak() {
+        if (textToSpeech != null && textToSpeech.isSpeaking()) {
+            textToSpeech.stop();
+            speechTextList.clear();
+            isStop = true;
+            speakIndex = 0;
+            Log.d(TAG, "stop speak");
+        }
+    }
+
+    public void removeSpeak(String text) {
+        synchronized (lockObject) {
+            if (!TextUtils.isEmpty(text) && !TextUtils.isEmpty(speakSpeech)) {
+                if (text.equals(speakSpeech) && textToSpeech.isSpeaking()) {
+                    textToSpeech.stop();
+                    speechTextList.remove(text);
+                    isStop = true;
+                    speakIndex = 0;
+                } else {
+                    speechTextList.remove(text);
+                }
+            }
+        }
+    }
+
+    public void setSpeechLoopCount(int count) {
+        loopCount = count;
+    }
+
+    public void release() {
+        speechTextList.clear();
+        isStop = true;
+        speakIndex = 0;
+        if (textToSpeech != null) {
+            textToSpeech.stop();
+            textToSpeech.shutdown();
+            textToSpeech = null;
+        }
+    }
+
+    public void startSpeechThread() {
+        if (null == speechThread) {
+            speechThread = new Thread(new SpeechRunnable());
+            speechThread.start();
+        } else if (!speechThread.isAlive()) {
+            speechThread.start();
+        }
+    }
+
+    public class SpeechRunnable implements Runnable {
+        public void run() {
+            while (isSpeechLoop) {
+                //synchronized (lockObject) {
+                    if (speechTextList.size() > 0 && isStop) {
+                        speakSpeech = speechTextList.get(0);
+                        Log.d(TAG, "speakSpeech: " + speakSpeech);
+                        speak(speakSpeech);
+
+                        //if (speechTextList.contains(speakSpeech)) {
+                            speechTextList.remove(speakSpeech);
+                        //}
+                    }
+                //}
+
+                try {
+                    Thread.sleep(50);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public TextToSpeech getTextToSpeech() {
+        return textToSpeech;
+    }
+
+    public Thread getSpeechThread() {
+        return speechThread;
+    }
+}

+ 101 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/UpdateTipsDialogHelper.java

@@ -0,0 +1,101 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.os.CountDownTimer;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.activity.AppUpdateActivity;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+public class UpdateTipsDialogHelper {
+
+    private static AlertDialog dialog;
+
+    public static void showDialog(Activity activity) {
+        if (dialog != null && dialog.isShowing()) {
+            return;
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.update_tips_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        Button buttonCancel = contentView.findViewById(R.id.cancel_button);
+        Button buttonConfirm = contentView.findViewById(R.id.confirm_button);
+        final CountDownTimer timer = new CountDownTimer(30000, 1000) {
+
+            @Override
+            public void onTick(long millisUntilFinished) {
+                String text = BaseApplication.appContext.getString(R.string.confirm_down_time, millisUntilFinished/1000);
+                buttonConfirm.setText(text);
+            }
+
+            @Override
+            public void onFinish() {
+                Intent intent = new Intent();
+                intent.setClass(activity, AppUpdateActivity.class);
+                activity.startActivity(intent);
+
+                if (dialog != null) {
+                    dialog.dismiss();
+                }
+            }
+        };
+        timer.start();
+
+        buttonCancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Constant.APP_UPDATING = false;
+                if (timer != null) {
+                    timer.cancel();
+                }
+                if (dialog != null) {
+                    dialog.dismiss();
+                }
+            }
+        });
+
+        buttonConfirm.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (timer != null) {
+                    timer.cancel();
+                }
+
+                Intent intent = new Intent();
+                intent.setClass(activity, AppUpdateActivity.class);
+                activity.startActivity(intent);
+
+                if (dialog != null) {
+                    dialog.dismiss();
+                }
+            }
+        });
+
+        dialog = builder.create();
+        dialog.setCanceledOnTouchOutside(false);
+        dialog.setCancelable(false);
+        dialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = dialog.getWindow();
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 640;
+            lp.height = 420;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 68 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/Util.kt

@@ -0,0 +1,68 @@
+package com.wdkl.app.ncs.callingbed.helper
+
+import android.annotation.SuppressLint
+import android.app.KeyguardManager
+import android.content.Context
+import android.content.Context.KEYGUARD_SERVICE
+import android.os.PowerManager
+import android.util.DisplayMetrics
+import android.view.WindowManager
+import com.wdkl.ncs.android.lib.base.BaseApplication
+
+
+object Util {
+
+    /**
+     * 亮屏并解锁
+     */
+    @SuppressLint("InvalidWakeLockTag")
+    fun wakeUpAndUnlock(): PowerManager.WakeLock? {
+        val pm = BaseApplication.appContext.getSystemService(Context.POWER_SERVICE) as PowerManager
+        var wakeLock: PowerManager.WakeLock? = null
+
+        val screenOn = pm.isInteractive
+        if (!screenOn) { //如果是熄灭状态
+            wakeLock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG")
+            wakeLock.acquire(10000)//亮屏
+        }
+
+        // 屏幕解锁
+        val keyguardManager = BaseApplication.appContext.getSystemService(KEYGUARD_SERVICE) as KeyguardManager
+        val keyguardLock = keyguardManager.newKeyguardLock("unLock")
+        // 屏幕锁定
+        keyguardLock.reenableKeyguard()
+        keyguardLock.disableKeyguard() // 解锁
+        return wakeLock
+    }
+
+    @SuppressLint("InvalidWakeLockTag")
+    fun getCpuWakeLock(context: Context): PowerManager.WakeLock? {
+        val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
+        val cpuWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                context.javaClass.canonicalName)
+        return cpuWakeLock
+    }
+
+    fun appendSpace(para: String): String? {
+        val length = para.length
+        val value = CharArray(length shl 1)
+        var i = 0
+        var j = 0
+        while (i < length) {
+            value[j] = para[i]
+            value[1 + j] = ' '
+            ++i
+            j = i shl 1
+        }
+        return String(value)
+    }
+
+
+
+    fun getPixelsFromDp(context: Context, size: Int): Int {
+        val metrics = DisplayMetrics()
+        val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+        wm.getDefaultDisplay().getMetrics(metrics)
+        return size * metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT
+    }
+}

+ 110 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/Utils.java

@@ -0,0 +1,110 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.zhyl.ZhylManager;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.Camera;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+import java.lang.reflect.Method;
+
+public class Utils {
+
+    public static final int STATUS_BAR_DISABLE_HOME = 0x00200000;
+    public static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
+    public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000;
+    public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000;//4.2以上的整形标识
+    public static final int STATUS_BAR_DISABLE_NONE = 0x00000000;//取消StatusBar所有disable属性,即还原到最最原始状态
+
+    public static void checkCameraSupport() {
+        int num = Camera.getNumberOfCameras();
+        if (num > 0) {
+            Constant.supportCamera = true;
+        } else {
+            Constant.supportCamera = false;
+        }
+    }
+
+    public static void setStatusBarDisable(Context context, int disable_status) {//调用statusBar的disable方法
+        Object service = context.getSystemService("statusbar");
+        try {
+            Class<?> statusBarManager = Class.forName
+                    ("android.app.StatusBarManager");
+            Method expand = statusBarManager.getMethod("disable", int.class);
+            expand.invoke(service, disable_status);
+        } catch (Exception e) {
+            unBanStatusBar(context);
+            e.printStackTrace();
+        }
+    }
+
+    public static void unBanStatusBar(Context context) {//利用反射解除状态栏禁止下拉
+        Object service = context.getSystemService("statusbar");
+        try {
+            Class<?> statusBarManager = Class.forName
+                    ("android.app.StatusBarManager");
+            Method expand = statusBarManager.getMethod("disable", int.class);
+            expand.invoke(service, STATUS_BAR_DISABLE_NONE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void hideStatusBar(Context context, boolean hide) {
+        if(BuildConfig.flag.equals(Constant.DEV_W_DCH)) {
+            hideStatusBarDch(context, hide);
+        } else if (BuildConfig.flag.equals(Constant.DEV_W_YLD)) {
+            hideStatusBarYld(context, hide);
+        } else if (BuildConfig.flag.equals(Constant.DEV_W_A133)) {
+            try {
+                ZhylManager zhylManager = ZhylManager.getInstance(BaseApplication.appContext);
+                //隐藏虚拟导航栏
+                zhylManager.disp_setNavigationBar(!hide);
+            } catch (Exception e) {
+                //
+            }
+        }
+    }
+
+    //是否隐藏系统栏
+    public static void hideStatusBarDch(Context context, boolean hide) {
+        Log.d("StatusBar", "toggleStatusBar: hide ===== " + hide);
+        Intent intent = new Intent();
+        intent.setAction("control.nav.hide");//虚拟按键
+        if (hide) {
+            intent.putExtra("hide", "1");//关闭
+        } else {
+            intent.putExtra("hide", "0");//开启
+        }
+        context.sendBroadcast(intent);
+    }
+
+    //是否隐藏系统栏
+    public static void hideStatusBarYld(Context context, boolean hide) {
+        Intent intent = new Intent();
+        if (hide) {
+            intent.setAction("com.elclcd.hidebar");
+        } else {
+            intent.setAction("com.elclcd.unhidebar");
+        }
+        context.sendBroadcast(intent);
+    }
+
+    //隐藏软键盘
+    public static void hideInputKeyboard(IBinder token) {
+        try {
+            Log.d("keyboard", "hide input keyboard ===== ");
+            InputMethodManager mInputKeyBoard = (InputMethodManager) BaseApplication.appContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+            mInputKeyBoard.hideSoftInputFromWindow(token, 0);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 188 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/VoiceManagerUtil.java

@@ -0,0 +1,188 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.content.Context;
+import android.media.AudioManager;
+
+/**
+ * 类名称:VoiceManagerUtil <br>
+ * 类描述:声音控制工具类 <br>
+ * 创建人:Waderson Shll (TEL:15675117662)<br>
+ * 创建时间:2018-03-15 <br>
+ * 特别提醒:如有需要该类可任意创建与调用;在未通知本人的情况下该类禁止任何修改!<br>
+ */
+public class VoiceManagerUtil {
+    /**
+     * 获取提示音音量最大值
+     *
+     * @param context
+     */
+    public static int getAlarmMax(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM);
+    }
+
+    /**
+     * 获取提示音音量当前值
+     *
+     * @param context
+     */
+    public static int getAlarmNow(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
+    }
+
+    /**
+     * 获取多媒体音量最大值
+     *
+     * @param context
+     */
+    public static int getMusicMax(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+    }
+
+    /**
+     * 获取多媒体音量当前值
+     *
+     * @param context
+     */
+    public static int getMusicNow(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+    }
+
+    /**
+     * 获取铃声音量最大值
+     *
+     * @param context
+     */
+    public static int getRingMax(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
+    }
+
+    /**
+     * 获取铃声音量当前值
+     *
+     * @param context
+     */
+    public static int getRingNow(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
+    }
+
+    /**
+     * 获取系统音量最大值
+     *
+     * @param context
+     */
+    public static int getSystemMax(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
+    }
+
+    /**
+     * 获取系统音量当前值
+     *
+     * @param context
+     */
+    public static int getSystemNow(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
+    }
+
+    /**
+     * 获取通话音量最大值
+     *
+     * @param context
+     */
+    public static int getCallMax(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
+    }
+
+    /**
+     * 获取通话音量当前值
+     *
+     * @param context
+     */
+    public static int getCallNow(Context context) {
+        AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        return mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+    }
+
+    /**
+     * 设置提示音音量
+     *
+     * @param context
+     * @param percent (百分比;只能0--100之间)
+     */
+    public static void setAlarmVoice(Context context, int percent) {
+        float vPercent=((float)percent)/100f;
+        vPercent = vPercent < 0 ? 0 : vPercent;
+        vPercent = vPercent > 1 ? 1 : vPercent;
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setStreamVolume(AudioManager.STREAM_ALARM, (int) (getAlarmMax(context) * vPercent), 0);
+    }
+
+    /**
+     * 设置多媒体音量
+     *
+     * @param context
+     * @param percent (百分比;只能0--100之间)
+     */
+    public static void setMusicVoice(Context context, int percent) {
+        float vPercent=((float)percent)/100f;
+        vPercent = vPercent < 0 ? 0 : vPercent;
+        vPercent = vPercent > 1 ? 1 : vPercent;
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) (getMusicMax(context) * vPercent), 0);
+    }
+
+    /**
+     * 设置铃声音量
+     *
+     * @param context
+     * @param percent (百分比;只能0--100之间)
+     */
+    public static void setRingVoice(Context context, int percent) {
+        float vPercent=((float)percent)/100f;
+        vPercent = vPercent < 0 ? 0 : vPercent;
+        vPercent = vPercent > 1 ? 1 : vPercent;
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setStreamVolume(AudioManager.STREAM_RING, (int) (getRingMax(context) * vPercent), 0);
+    }
+
+    /**
+     * 设置系统音量
+     *
+     * @param context
+     * @param percent (百分比;只能0--100之间)
+     */
+    public static void setSystemVoice(Context context, int percent) {
+        float vPercent=((float)percent)/100f;
+        vPercent = vPercent < 0 ? 0 : vPercent;
+        vPercent = vPercent > 1 ? 1 : vPercent;
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, (int) (getSystemMax(context) * vPercent), 0);
+    }
+
+    /**
+     * 设置通话音量
+     *
+     * @param context
+     * @param percent (百分比;只能0--100之间)
+     */
+    public static void setCallVoice(Context context, int percent) {
+        float vPercent=((float)percent)/100f;
+        vPercent = vPercent < 0 ? 0 : vPercent;
+        vPercent = vPercent > 1 ? 1 : vPercent;
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, (int) (getCallMax(context) * vPercent), 0);
+    }
+
+    public static void setAudioMode(Context context, int mode) {
+        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        audioManager.setMode(mode);
+    }
+}

+ 57 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/WarningDialogHelper.java

@@ -0,0 +1,57 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.wdkl.app.ncs.callingbed.R;
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory;
+
+public class WarningDialogHelper {
+    private static AlertDialog dialog;
+
+    public static void showDialog(Activity activity) {
+        if (dialog != null && dialog.isShowing()) {
+            return;
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.warning_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        Button button = contentView.findViewById(R.id.cancel_button);
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                HardWareFactory.getHardTools().Registration(activity);
+            }
+        });
+
+        dialog = builder.create();
+        //dialog.setCanceledOnTouchOutside(false);
+        //dialog.setCancelable(false);
+        dialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = dialog.getWindow();
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 600;
+            lp.height = 240;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismiss() {
+        if (dialog != null && dialog.isShowing()) {
+            dialog.dismiss();
+        }
+    }
+}

+ 248 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/helper/XCrashUtils.java

@@ -0,0 +1,248 @@
+package com.wdkl.app.ncs.callingbed.helper;
+
+import android.app.AlarmManager;
+import android.app.Application;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.util.Log;
+
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.app.ncs.callingbed.hardware.HardWareFactory;
+import com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity;
+import com.wdkl.ncs.android.middleware.api.UrlManager;
+
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.FormBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import xcrash.ICrashCallback;
+import xcrash.TombstoneManager;
+import xcrash.TombstoneParser;
+import xcrash.XCrash;
+
+public class XCrashUtils {
+    private final static String TAG = "XCrashUtils";
+
+    private Application app;
+    private OkHttpClient okHttpClient;
+
+    // callback for java crash, native crash and ANR
+    private final ICrashCallback callback = new ICrashCallback() {
+        @Override
+        public void onCrash(String logPath, String emergency) {
+            Log.d(TAG, "log path: " + (logPath != null ? logPath : "(null)") + ", emergency: " + (emergency != null ? emergency : "(null)"));
+
+            //打开虚拟导航栏
+            Utils.hideStatusBar(app, false);
+
+            if (emergency != null) {
+                debug(logPath, emergency);
+
+                // Disk is exhausted, send crash report immediately.
+                //sendThenDeleteCrashLog(logPath, emergency);
+            } else {
+                // Add some expanded sections. Send crash report at the next time APP startup.
+
+                // OK
+                TombstoneManager.appendSection(logPath, "expanded_key_1", "expanded_content");
+                TombstoneManager.appendSection(logPath, "expanded_key_2", "expanded_content_row_1\nexpanded_content_row_2");
+
+                // Invalid. (Do NOT include multiple consecutive newline characters ("\n\n") in the content string.)
+                // TombstoneManager.appendSection(logPath, "expanded_key_3", "expanded_content_row_1\n\nexpanded_content_row_2");
+
+                debug(logPath, null);
+            }
+
+            // Disk is exhausted, send crash report immediately.
+            //sendThenDeleteCrashLog(logPath, emergency);
+
+            //非debug版本上传crash日志
+            if (!BuildConfig.DEBUG) {
+                uploadCrashLog(logPath);
+            } else {
+                restartApp();
+            }
+        }
+    };
+
+    //ANR Catcher
+    private final ICrashCallback anrCallback = new ICrashCallback() {
+        @Override
+        public void onCrash(String logPath, String emergency) {
+            Log.d(TAG, "log path: " + (logPath != null ? logPath : "(null)") + ", emergency: " + (emergency != null ? emergency : "(null)"));
+
+            //打开虚拟导航栏
+            Utils.hideStatusBar(app, false);
+
+            if (emergency != null) {
+                debug(logPath, emergency);
+
+                // Disk is exhausted, send crash report immediately.
+                //sendThenDeleteCrashLog(logPath, emergency);
+            } else {
+                // Add some expanded sections. Send crash report at the next time APP startup.
+
+                // OK
+                TombstoneManager.appendSection(logPath, "expanded_key_1", "expanded_content");
+                TombstoneManager.appendSection(logPath, "expanded_key_2", "expanded_content_row_1\nexpanded_content_row_2");
+
+                // Invalid. (Do NOT include multiple consecutive newline characters ("\n\n") in the content string.)
+                // TombstoneManager.appendSection(logPath, "expanded_key_3", "expanded_content_row_1\n\nexpanded_content_row_2");
+
+                debug(logPath, null);
+            }
+            HardWareFactory.getHardTools().Registration(app);
+
+//            if (Build.MODEL.equals("rk3128") || Build.MODEL.equals("rk3288")) {
+//                HardWareFactory.getHardTools().Registration(app);
+//            } else {
+//                AppUpdateHelper.restartApp(app);
+//            }
+        }
+    };
+
+    public void init(Application application) {
+        Log.d(TAG, "xCrash SDK init: start");
+        app = application;
+
+        // Initialize xCrash.
+        XCrash.init(application, new XCrash.InitParameters()
+                .setAppVersion(BuildConfig.VERSION_NAME)
+                .setJavaRethrow(true)
+                .setJavaLogCountMax(10)
+                .setJavaDumpAllThreadsWhiteList(new String[]{"^main$", "^Binder:.*", ".*Finalizer.*"})
+                .setJavaDumpAllThreadsCountMax(10)
+                .setJavaCallback(callback)
+                .setNativeRethrow(true)
+                .setNativeLogCountMax(10)
+                .setNativeDumpAllThreadsWhiteList(new String[]{"^xcrash\\.sample$", "^Signal Catcher$", "^Jit thread pool$", ".*(R|r)ender.*", ".*Chrome.*"})
+                .setNativeDumpAllThreadsCountMax(10)
+                .setNativeCallback(callback)
+                .setAnrRethrow(true)
+                .setAnrLogCountMax(10)
+                .setAnrCallback(anrCallback)
+                .setPlaceholderCountMax(3)
+                .setPlaceholderSizeKb(64)
+                .setLogDir(application.getExternalFilesDir("xcrash").toString())
+                .setLogFileMaintainDelayMs(5000));
+    }
+
+    private void uploadCrashLog(String path) {
+        final File logFile = new File(path);
+        if (logFile.exists()) {
+            final UrlManager urlManager = UrlManager.Companion.build();
+            String url = urlManager.getBase() + "ncs/upload/file";
+            HttpHelper.upload(url, logFile, TAG, new HttpHelper.UploadCallback() {
+                @Override
+                public void onFail() {
+                    Log.e(TAG,"错误日志文件上传失败!");
+                    restartApp();
+                }
+
+                @Override
+                public void onSuccess(String data) {
+                    Log.e(TAG,"错误日志文件上传成功!" + data);
+                    sendThenDeleteCrashLog(urlManager.getBase() + data, null);
+                    //删除日志文件
+                    //logFile.delete();
+                }
+            });
+        }
+    }
+
+    private void sendThenDeleteCrashLog(final String logPath, String emergency) {
+        try {
+            // Parse
+            //Map<String, String> map = TombstoneParser.parse(logPath, emergency);
+            //String crashReport = new JSONObject(map).toString();
+
+            if(okHttpClient == null){
+                okHttpClient = new OkHttpClient();
+            }
+
+            FormBody.Builder formBody = new FormBody.Builder();
+            formBody.add("class_name", app.getPackageName());
+            formBody.add("method_name", "");
+            formBody.add("exception_name", "");
+            formBody.add("err_msg", "");
+            formBody.add("stack_trace", logPath);
+
+            UrlManager urlManager = UrlManager.Companion.build();
+            Request request  = new Request.Builder()
+                    .url(urlManager.getBase() + "device/error_log")
+                    .post(formBody.build())
+                    .build();
+
+            okHttpClient.newCall(request).enqueue(new Callback() {
+                @Override
+                public void onFailure(Call call, IOException e) {
+                    Log.e(TAG,"错误日志名称上传失败"+e.getMessage());
+                    restartApp();
+                }
+
+                @Override
+                public void onResponse(Call call, Response response) throws IOException {
+                    Log.d(TAG,"错误日志名称上传成功");
+                    TombstoneManager.deleteTombstone(logPath);
+                    //String data = response.body().string();
+                    //Log.d(TAG,"错误日志数据 data "+data);
+                    restartApp();
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        // Send the crash report to server-side.
+        // ......
+
+        // If the server-side receives successfully, delete the log file.
+        //
+        // Note: When you use the placeholder file feature,
+        //       please always use this method to delete tombstone files.
+        //
+        //TombstoneManager.deleteTombstone(logPath);
+    }
+
+    private void debug(String logPath, String emergency) {
+        // Parse and save the crash info to a JSON file for debugging.
+        FileWriter writer = null;
+        try {
+            File debug = new File(XCrash.getLogDir() + "/debug.json");
+            debug.createNewFile();
+            writer = new FileWriter(debug, false);
+            writer.write(new JSONObject(TombstoneParser.parse(logPath, emergency)).toString());
+        } catch (Exception e) {
+            Log.d(TAG, "debug failed", e);
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception ignored) {
+                }
+            }
+        }
+    }
+    private void restartApp() {
+        //重新启动app
+        Intent mStartActivity = new Intent(app.getApplicationContext(), WelcomeActivity.class);
+        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+        int mPendingIntentId = 123456;
+        PendingIntent mPendingIntent = PendingIntent.getActivity(app.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+        AlarmManager mgr = (AlarmManager) app.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, mPendingIntent);
+        android.os.Process.killProcess(android.os.Process.myPid());
+        System.exit(0);
+    }
+
+}

+ 20 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/launch/CallingbedLaunch.kt

@@ -0,0 +1,20 @@
+package com.wdkl.app.ncs.callingbed.launch
+
+import com.enation.javashop.android.jrouter.external.annotation.Router
+import com.wdkl.app.ncs.callingbed.di.CallingbedComponent
+import com.wdkl.app.ncs.callingbed.di.DaggerCallingbedComponent
+import com.wdkl.ncs.android.lib.base.BaseLaunch
+import com.wdkl.ncs.android.middleware.di.DaggerManager
+
+@Router(path = "/callingbed/launch")
+class CallingbedLaunch :BaseLaunch() {
+    companion object {
+        lateinit var component:CallingbedComponent
+    }
+
+    override fun moduleInit() {
+        component = DaggerCallingbedComponent.builder()
+                .applicationComponent(DaggerManager.APPLICATION_COMPONENT)
+                .build()
+    }
+}

+ 64 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/service/ViewService.java

@@ -0,0 +1,64 @@
+package com.wdkl.app.ncs.callingbed.service;
+
+
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.wdkl.app.ncs.callingbed.R;
+
+public class ViewService extends Service {
+
+
+    private WindowManager windowManager;
+    private Button button;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        showOver();
+
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        windowManager.removeView(button);
+    }
+
+    private void showOver() {
+        button = new Button(this);
+
+        button.setBackgroundResource(R.color.content_color);
+
+        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
+        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        } else {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
+        }
+        layoutParams.width = 60;
+        layoutParams.height =60;
+        layoutParams.x = 0 ;
+        layoutParams.y = 0 ;
+        layoutParams.gravity = Gravity.LEFT | Gravity.TOP ;
+        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        layoutParams.format = PixelFormat.RGBA_8888 | PixelFormat.TRANSLUCENT;
+        windowManager.addView(button, layoutParams);
+    }
+
+}
+

+ 509 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/settings/SettingConfig.java

@@ -0,0 +1,509 @@
+package com.wdkl.app.ncs.callingbed.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+
+public class SettingConfig {
+
+
+    private static final String SP_NAME = "SP_BED_FUNCTION";
+
+    //白昼设置白天的初始时间设置
+    private static final String KEY_SP_INITIAL_DAY_TIME = "KEY_SP_INITIAL_DAY_TIME";
+    private static final String initial_day_time = "07:00";
+    private static final String KEY_SP_INITIAL_DAY_TIME_LOCATION = "KEY_SP_INITIAL_DAY_TIME_LOCATION";
+    private static final String initial_day_time_location = "12";
+
+
+    //白昼设置白天的结束时间设置
+    private static final String KEY_SP_END_OF_DAY = "KEY_SP_END_OF_DAY";
+    private static final String end_of_day = "19:00";
+    //白昼设置白天的结束时间设置
+    private static final String KEY_SP_END_OF_DAY_LOCATION = "KEY_SP_END_OF_DAY_LOCATION";
+    private static final String end_of_day_location = "38";
+
+
+    //分机白天亮度
+    private static final String KEY_SP_EXTENSION_DAYTIME_BRIGHTNESS = "KEY_SP_EXTENSION_DAYTIME_BRIGHTNESS";
+    private static final int extension_daytime_brightness = 80;
+    //分机晚上亮度
+    private static final String KEY_SP_EXTENSION_NIGHT_BRIGHTNESS = "KEY_SP_EXTENSION_NIGHT_BRIGHTNESS";
+    private static final int extension_night_brightness = 50;
+
+    //分机LED白天亮度
+    private static final String KEY_SP_EXTENSION_DAYTIME_LED_BRIGHTNESS = "KEY_SP_EXTENSION_DAYTIME_LED_BRIGHTNESS";
+    private static final int extension_daytime_led_brightness = 80;
+    //分机LED晚上亮度
+    private static final String KEY_SP_EXTENSION_NIGHT_LED_BRIGHTNESS = "KEY_SP_EXTENSION_NIGHT_LED_BRIGHTNESS";
+    private static final int extension_night_led_brightness = 50;
+
+    //分机白天系统音量
+    private static final String KEY_SP_EXTENSION_DAYTIME_SYSTEM_VOLUME = "KEY_SP_EXTENSION_DAYTIME_SYSTEM_VOLUME";
+    private static final int extension_daytime_system_volume = 100;
+    //分机晚上系统音量
+    private static final String KEY_SP_EXTENSION_NIGHT_SYSTEM_VOLUME = "KEY_SP_EXTENSION_NIGHT_SYSTEM_VOLUME";
+    private static final int extension_night_system_volume = 70;
+
+    //分机手柄录入音量
+    private static final String KEY_SP_THE_EXTENSION_HANDLR_RECORDS_THE_VOLUME = "KEY_SP_THE_EXTENSION_HANDLR_RECORDS_THE_VOLUME";
+    private static final int the_extension_handle_records_the_volume = 50;
+
+    //分机通话音量
+    private static final String KEY_SP_EXTENSION_CALL_VOLUME = "KEY_SP_EXTENSION_CALL_VOLUME";
+    private static final int extension_call_volume = 80;
+
+    //呼叫超时时间
+    private static final String KEY_SP_SIP_OVERTIME = "KEY_SP_SIP_OVERTIME";
+    private static final int sip_over_time = 30;
+
+    //息屏超时时间
+    private static final String KEY_SP_SLEEP_TIME = "KEY_SP_SLEEP_TIME";
+    private static final int sleep_time = 30;
+
+    //网络异常重启次数
+    private static final String KEY_SP_NET_ERR_RESET_COUNT = "KEY_SP_NET_ERR_RESET_COUNT";
+
+    //是否自动接通
+    private static final String KEY_SP_AUTO_ANSWER = "KEY_SP_AUTO_ANSWER";
+
+    private static final String KEY_SP_BROADCAST_VOLUME = "KEY_SP_BROADCAST_VOLUME";
+    private static final String KEY_SP_RECORD_ENABLE = "KEY_SP_RECORD_ENABLE";
+
+    //是否使用sip通话
+    private static final String KEY_SP_SIP_ENABLE = "KEY_SP_SIP_ENABLE";
+
+    //护理状态
+    private static final String KEY_IN_NURSING = "KEY_IN_NURSING";
+    private static final String KEY_NURSING_ID = "KEY_NURSING_ID";
+
+    //麦克风增益
+    private static final String KEY_SP_MIC_ENABLE = "KEY_SP_MIC_ENABLE";
+
+    //喇叭增益
+    private static final String KEY_SP_HORN_ENABLE = "KEY_SP_HORN_ENABLE";
+
+    //是否开启蓝牙网关
+    private static final String KEY_SP_BLUETOOTH_GATEWAY = "KEY_SP_BLUETOOTH_GATEWAY";
+
+    //是否开启433串口
+    private static final String KEY_SP_433_GATEWAY = "KEY_SP_433_GATEWAY";
+
+    //是否开启床垫服务
+    private static final String KEY_SP_SLEEP_GATEWAY = "KEY_SP_SLEEP_GATEWAY";
+
+
+    //是否设备场景类型 //医院 月子中心 养老 公寓
+    private static final String KEY_SP_Scene_type= "KEY_SP_Scene_type";
+
+    //是否设备apk类型
+    private static final String KEY_SP_APK_TYPE= "KEY_SP_APK_TYPE";
+
+    //屏幕方向
+    private static final String KEY_SP_window= "KEY_SP_window";
+
+    public static void setScene(Context context, int mode) {
+        getEditor(context).putInt(KEY_SP_Scene_type, mode).apply();
+    }
+
+    public static int getScene(Context context) {
+        return getSP(context).getInt(KEY_SP_Scene_type, 0);
+    }
+
+    public static void setAPK(Context context, int mode) {
+        getEditor(context).putInt(KEY_SP_Scene_type, mode).apply();
+    }
+
+    public static int getAPK(Context context) {
+        return getSP(context).getInt(KEY_SP_Scene_type, 0);
+    }
+
+    public static void setwindow(Context context, int mode) {
+        getEditor(context).putInt(KEY_SP_Scene_type, mode).apply();
+    }
+
+    public static int getwindow(Context context) {
+        return getSP(context).getInt(KEY_SP_Scene_type, 0);
+    }
+
+
+
+
+
+    public static void setMIC(Context context, int mode) {
+        getEditor(context).putInt(KEY_SP_MIC_ENABLE, mode).apply();
+    }
+
+    public static int getMic(Context context) {
+        return getSP(context).getInt(KEY_SP_MIC_ENABLE, 0);
+    }
+    public static void setHORN(Context context, int mode) {
+        getEditor(context).putInt(KEY_SP_HORN_ENABLE, mode).apply();
+    }
+
+    public static int getHORN(Context context) {
+        return getSP(context).getInt(KEY_SP_HORN_ENABLE, 0);
+    }
+
+
+
+    public static boolean get433GatewayOn(Context context) {
+        return getSP(context).getBoolean(KEY_SP_433_GATEWAY, false);
+    }
+
+    public static void set433GatewayOn(Context context, boolean on) {
+        getEditor(context).putBoolean(KEY_SP_433_GATEWAY, on).apply();
+    }
+
+    public static boolean getSLEEPGatewayOn(Context context) {
+        return getSP(context).getBoolean(KEY_SP_SLEEP_GATEWAY, false);
+    }
+
+    public static void setSLEEPGatewayOn(Context context, boolean on) {
+        getEditor(context).putBoolean(KEY_SP_SLEEP_GATEWAY, on).apply();
+    }
+
+    public static boolean getBluetoothGatewayOn(Context context) {
+        return getSP(context).getBoolean(KEY_SP_BLUETOOTH_GATEWAY, false);
+    }
+
+    public static void setBluetoothGatewayOn(Context context, boolean on) {
+        getEditor(context).putBoolean(KEY_SP_BLUETOOTH_GATEWAY, on).apply();
+    }
+
+    public static int getNursingId(Context context) {
+        return getSP(context).getInt(KEY_NURSING_ID, -1);
+    }
+
+    public static void setNursingId(Context context, int nursingId) {
+        getEditor(context).putInt(KEY_NURSING_ID, nursingId).apply();
+    }
+
+    public static boolean getInNursing(Context context) {
+        return getSP(context).getBoolean(KEY_IN_NURSING, false);
+    }
+
+    public static void setInNursing(Context context, boolean nursing) {
+        getEditor(context).putBoolean(KEY_IN_NURSING, nursing).apply();
+    }
+
+    public static int getBroadcastVol(Context context) {
+        return getSP(context).getInt(KEY_SP_BROADCAST_VOLUME, 80);
+    }
+
+    public static void setBroadcastVol(Context context, int vol) {
+        getEditor(context).putInt(KEY_SP_BROADCAST_VOLUME, vol).apply();
+    }
+
+    public static boolean getRecordEnable(Context context) {
+        return getSP(context).getBoolean(KEY_SP_RECORD_ENABLE, false);
+    }
+
+    public static void setRecordEnable(Context context, boolean enable) {
+        getEditor(context).putBoolean(KEY_SP_RECORD_ENABLE, enable).apply();
+    }
+
+    public static boolean getSipEnabled(Context context) {
+        return getSP(context).getBoolean(KEY_SP_SIP_ENABLE, false);
+    }
+
+    public static void setSipEnable(Context context, boolean enable) {
+        getEditor(context).putBoolean(KEY_SP_SIP_ENABLE, enable).apply();
+    }
+
+    /**
+     * 获取分机白天亮度
+     *
+     * @return
+     */
+    public static int getExtensionDaytimeBrightness(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_DAYTIME_BRIGHTNESS, extension_daytime_brightness);
+    }
+
+    /**
+     * 设置分机白天亮度
+     *
+     * @param value
+     */
+    public static void setExtensionDaytimeBrightness(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_DAYTIME_BRIGHTNESS, value).apply();
+    }
+
+    /**
+     * 获取分机晚上亮度
+     *
+     * @return
+     */
+    public static int getExtensionNightBrightness(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_NIGHT_BRIGHTNESS, extension_night_brightness);
+    }
+
+    /**
+     * 设置分机晚上亮度
+     *
+     * @param value
+     */
+    public static void setExtensionNightBrightness(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_NIGHT_BRIGHTNESS, value).apply();
+    }
+
+    /**
+     * 获取分机LED白天亮度
+     *
+     * @return
+     */
+    public static int getExtensionDaytimeLEDBrightness(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_DAYTIME_LED_BRIGHTNESS, extension_daytime_led_brightness);
+    }
+
+    /**
+     * 设置分机LED白天亮度
+     *
+     * @param value
+     */
+    public static void setExtensionDaytimeLEDBrightness(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_DAYTIME_LED_BRIGHTNESS, value).apply();
+    }
+
+    /**
+     * 获取分机LED晚上亮度
+     *
+     * @return
+     */
+    public static int getExtensionNightLEDBrightness(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_NIGHT_LED_BRIGHTNESS, extension_night_led_brightness);
+    }
+
+    /**
+     * 设置分机LED晚上亮度
+     *
+     * @param value
+     */
+    public static void setExtensionNightLEDBrightness(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_NIGHT_LED_BRIGHTNESS, value).apply();
+    }
+
+
+    /**
+     * 获取分机白天系统音量
+     *
+     * @return
+     */
+    public static int getExtensionDaytimeSystemVolume(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_DAYTIME_SYSTEM_VOLUME, extension_daytime_system_volume);
+    }
+
+    /**
+     * 设置分机白天系统音量
+     *
+     * @param value
+     */
+    public static void setExtensionDaytimeSystemVolume(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_DAYTIME_SYSTEM_VOLUME, value).apply();
+    }
+
+    /**
+     * 获取分机晚上系统音量
+     *
+     * @return
+     */
+    public static int getExtensionNightSystemVolume(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_NIGHT_SYSTEM_VOLUME, extension_night_system_volume);
+    }
+
+    /**
+     * 设置分机晚上系统音量
+     *
+     * @param value
+     */
+    public static void setExtensionNightSystemVolume(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_NIGHT_SYSTEM_VOLUME, value).apply();
+    }
+
+
+
+    /**
+     * 获取分机手柄录入音量
+     *
+     * @return
+     */
+    public static int getTheExtensionHandleRecordsTheVolume(Context context) {
+        return getSP(context).getInt(KEY_SP_THE_EXTENSION_HANDLR_RECORDS_THE_VOLUME, the_extension_handle_records_the_volume);
+    }
+
+    /**
+     * 设置分机手柄录入音量
+     *
+     * @param value
+     */
+    public static void setTheExtensionHandleRecordsTheVolume(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_THE_EXTENSION_HANDLR_RECORDS_THE_VOLUME, value).apply();
+    }
+
+
+    /**
+     * 获取分机通话音量
+     *
+     * @return
+     */
+    public static int getExtensionCallVolume(Context context) {
+        return getSP(context).getInt(KEY_SP_EXTENSION_CALL_VOLUME, extension_call_volume);
+    }
+
+    /**
+     * 设置分机通话音量
+     *
+     * @param value
+     */
+    public static void setExtensionCallVolume(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_EXTENSION_CALL_VOLUME, value).apply();
+    }
+
+
+    /**
+     * 获取白昼设置白天的初始时间
+     *
+     * @return
+     */
+    public static String getInitialDayTime(Context context) {
+        return getSP(context).getString(KEY_SP_INITIAL_DAY_TIME, initial_day_time);
+    }
+
+    /**
+     * 设置白昼白天的初始时间
+     *
+     * @param value
+     */
+    public static void setInitialDayTime(Context context, String value) {
+        getEditor(context).putString(KEY_SP_INITIAL_DAY_TIME, value).apply();
+    }
+
+    /**
+     * 获取白昼设置白天的初始时间位置
+     *
+     * @return
+     */
+    public static String getInitialDayTimeLocation(Context context) {
+        return getSP(context).getString(KEY_SP_INITIAL_DAY_TIME_LOCATION, initial_day_time_location);
+    }
+
+    /**
+     * 设置白昼白天的初始时间位置
+     *
+     * @param value
+     */
+    public static void setInitialDayTimeLocation(Context context, String value) {
+        getEditor(context).putString(KEY_SP_INITIAL_DAY_TIME_LOCATION, value).apply();
+    }
+
+
+
+    /**
+     * 设置白昼白天的结束时间
+     *
+     * @param value
+     */
+    public static void setEndOfDay(Context context, String value) {
+        getEditor(context).putString(KEY_SP_END_OF_DAY, value).apply();
+    }
+
+    /**
+     * 获取白昼设置白天的结束时间
+     *
+     * @return
+     */
+    public static String getEndOfDay(Context context) {
+        return getSP(context).getString(KEY_SP_END_OF_DAY, end_of_day);
+    }
+
+    /**
+     * 设置白昼白天的结束时间位置
+     *
+     * @param value
+     */
+    public static void setEndOfDayLocation(Context context, String value) {
+        getEditor(context).putString(KEY_SP_END_OF_DAY_LOCATION, value).apply();
+    }
+
+    /**
+     * 获取白昼设置白天的结束时间位置
+     *
+     * @return
+     */
+    public static String getEndOfDayLocation(Context context) {
+        return getSP(context).getString(KEY_SP_END_OF_DAY_LOCATION, end_of_day_location);
+    }
+
+    /**
+     * 设置呼叫超时时间
+     *
+     * @param value
+     */
+    public static void setSipOverTime(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_SIP_OVERTIME, value).apply();
+    }
+
+    /**
+     * 获取呼叫超时时间
+     *
+     * @return
+     */
+    public static int getSipOverTime(Context context) {
+        return getSP(context).getInt(KEY_SP_SIP_OVERTIME, sip_over_time);
+    }
+
+    /**
+     * 设置息屏时间
+     *
+     * @param value
+     */
+    public static void setSleepTime(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_SLEEP_TIME, value).apply();
+    }
+
+    /**
+     * 获取息屏时间
+     *
+     * @return
+     */
+    public static int getSleepTime(Context context) {
+        return getSP(context).getInt(KEY_SP_SLEEP_TIME, sleep_time);
+    }
+
+    /**
+     * 获取网络异常重启次数
+     *
+     * @return
+     */
+    public static int getNetErrResetCount(Context context) {
+        return getSP(context).getInt(KEY_SP_NET_ERR_RESET_COUNT, 0);
+    }
+
+    /**
+     * 设置网络异常重启次数
+     *
+     * @param value
+     */
+    public static void setNetErrResetCount(Context context, int value) {
+        getEditor(context).putInt(KEY_SP_NET_ERR_RESET_COUNT, value).apply();
+    }
+
+    public static boolean getAutoAnswer(Context context) {
+        return getSP(context).getBoolean(KEY_SP_AUTO_ANSWER, false);
+    }
+
+    public static void setAutoAnswer(Context context, boolean value) {
+        getEditor(context).putBoolean(KEY_SP_AUTO_ANSWER, value).apply();
+    }
+
+
+    private static SharedPreferences getSP(Context context) {
+        return context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
+    }
+
+    private static SharedPreferences.Editor getEditor(Context context) {
+        return getSP(context).edit();
+    }
+
+
+}

+ 148 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepDataParse.java

@@ -0,0 +1,148 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+
+
+import android.os.Build;
+import android.util.Log;
+
+import com.clj.fastble.utils.HexUtil;
+import com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil;
+import com.wdkl.app.ncs.callingbed.bt_gateway.SignData;
+
+import java.nio.ByteBuffer;
+import java.time.Instant;
+
+import androidx.annotation.RequiresApi;
+
+
+public class SleepDataParse {
+
+    private final static String TAG = "SleepDataParse";
+
+    public static final int ACK_REQUIRED = 0x01;
+    public static final int NO_ACK_REQUIRED = 0x00;
+
+    private int dataLength; //数据长度
+    private int ackRequired;
+    private int messageSequence;
+    private int commandType;
+    private byte[] data;
+
+
+    //床垫数据 登录组装
+    public static byte[] parseValue(String result ,int Sequence) {
+        //体温: cd0f0076000004643320504102590064db019001db019001d9019101da019001da019001db019201d9019201da019001d9018f01dc019101db019001db019101da019101dc019101da019001da019101da019001db019101dc019001da018f01da019101d9019001da019101d9019101d90190015631303039fb
+        //sn号
+
+        String substring = result.substring(16, 29);
+        int ackRequired = SleepDataParse.ACK_REQUIRED;
+        int messageSequence = Sequence;
+        int commandType = 0x03;
+        byte[] data = HexUtil.hexStringToBytes(substring);
+        int dataLength = data.length+4;
+        SleepLoginDataParse dataPacket = new SleepLoginDataParse(dataLength, ackRequired, messageSequence, commandType, data);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+    //床垫数据 登录组装2
+    public static byte[] parseValue5(String result ,int Sequence) {
+        //体温: cd0f0076000004643320504102590064db019001db019001d9019101da019001da019001db019201d9019201da019001d9018f01dc019101db019001db019101da019101dc019101da019001da019101da019001db019101dc019001da018f01da019101d9019001da019101d9019101d90190015631303039fb
+        //sn号
+        int ackRequired = SleepDataParse.ACK_REQUIRED;
+        int messageSequence = Sequence;
+        int commandType = 0x03;
+        byte[] data = HexUtil.hexStringToBytes(result);
+        int dataLength = data.length+4;
+        SleepLoginDataParse dataPacket = new SleepLoginDataParse(dataLength, ackRequired, messageSequence, commandType, data);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+
+    //床垫数据 每秒上传
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    public static byte[] parseValue2(String result , int Sequence) {
+        //体温: cd0f0076  00 00 04 64 33 20 50 41 02 59 0064 db019001db019001d9019101da019001da019001db019201d9019201da019001d9018f01dc019101db019001db019101da019101dc019101da019001da019101da019001db019101dc019001da018f01da019101d9019001da019101d9019101d90190015631303039fb
+        //心率 //呼吸 //状态 //电池电量
+        String substring = result.substring(8, 28);
+        String heartRate = result.substring(32, 232)+"5E0964B8";
+
+        int ackRequired = SleepDataParse.NO_ACK_REQUIRED;
+        int messageSequence = Sequence;
+        int commandType = 0x0E;
+        long timestamp = Instant.now().getEpochSecond();
+        // 将时间戳转换为4个字节的时间戳(高位在前)
+        byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) timestamp).array();
+
+        byte[] data = HexUtil.hexStringToBytes(substring+heartRate);
+        byte[] results = concatByteArrays(timestampBytes, data);
+        int dataLength = results.length+4;
+        SleepLoginDataParse dataPacket = new SleepLoginDataParse(dataLength, ackRequired, messageSequence, commandType, results);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+    //床垫数据 分层上传
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    public static byte[] parseValue3(String result, int Sequence) {
+        //体温: cd0f0076000004643320504102590064db019001db019001d9019101da019001da019001db019201d9019201da019001d9018f01dc019101db019001db019101da019101dc019101da019001da019101da019001db019101dc019001da018f01da019101d9019001da019101d9019101d90190015631303039fb
+
+        int ackRequired = SleepDataParse.NO_ACK_REQUIRED;
+        int messageSequence = Sequence;
+        int commandType = 0x4E;
+        long timestamp = Instant.now().getEpochSecond();
+        // 将时间戳转换为4个字节的时间戳(高位在前)
+        byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) timestamp).array();
+        String substring = result.substring(8, 30)+"5E0964B8";
+        byte[] data = HexUtil.hexStringToBytes(substring);
+        byte[] results = concatByteArrays(timestampBytes, data);
+        int dataLength = results.length+4;
+        SleepLoginDataParse dataPacket = new SleepLoginDataParse(dataLength, ackRequired, messageSequence, commandType, results);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+    //床垫数据 蓝牙设置网络
+    public static byte[] parseValue4(String name, String Password) {
+        //名称以及密码以双引号包含,中间加逗号
+        String str = BluetoothUtil.strTo16(name +Password);
+        byte[] data =  HexUtil.hexStringToBytes(str);
+        Log.d(TAG, "发送配网数据: " + HexUtil.formatHexString(data, false));
+        byte[] dataLength = HexUtil.hexStringToBytes(BluetoothUtil.intToTwoBytesHexString( data.length+9));
+        SleepSetwifiDataParse dataPacket = new SleepSetwifiDataParse(dataLength, name, Password);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+    //设备数据确定组装
+    public static byte[] parseValue6(String result ) {
+        //体温: cd0f0076000004643320504102590064db019001db019001d9019101da019001da019001db019201d9019201da019001d9018f01dc019101db019001db019101da019101dc019101da019001da019101da019001db019101dc019001da018f01da019101d9019001da019101d9019101d90190015631303039fb
+        //sn号
+        int ackRequired = SleepDataParse.NO_ACK_REQUIRED;
+        int commandType = 0xF3;
+        byte[] data = HexUtil.hexStringToBytes(result);
+        int dataLength = data.length+4;
+        SleepLoginDataParse dataPacket = new SleepLoginDataParse(dataLength, ackRequired, ackRequired, commandType, data);
+        // 将 DataPacket 对象转换为字节数组
+        byte[] byteArray = dataPacket.toByteArray();
+        return byteArray;
+    }
+
+    private static byte[] concatByteArrays(byte[] a, byte[] b) {
+        byte[] result = new byte[a.length + b.length];
+        System.arraycopy(a, 0, result, 0, a.length);
+        System.arraycopy(b, 0, result, a.length, b.length);
+        return result;
+    }
+
+
+    public interface OnDataCallback {
+        void onData(String data);
+    }
+}

+ 59 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepLoginDataParse.java

@@ -0,0 +1,59 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+
+import java.io.ByteArrayOutputStream;
+
+public class SleepLoginDataParse {
+    public static final int FRAME_HEADER = 0x82;
+    public static final int ACK_REQUIRED = 0x01;
+    public static final int NO_ACK_REQUIRED = 0x00;
+
+    private int dataLength;
+    private int ackRequired;
+    private int messageSequence;
+    private int commandType;
+    private byte[] data;
+
+    public SleepLoginDataParse(int dataLength, int ackRequired, int messageSequence, int commandType, byte[] data) {
+        this.dataLength = dataLength;
+        this.ackRequired = ackRequired;
+        this.messageSequence = messageSequence;
+        this.commandType = commandType;
+        this.data = data;
+    }
+
+    public byte[] toByteArray() {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        // 帧头
+        outputStream.write(FRAME_HEADER);
+
+        // 长度
+        outputStream.write(dataLength);
+
+        // 应答要求
+        outputStream.write(ackRequired);
+
+        // 消息序号
+        outputStream.write(messageSequence);
+
+        // 命令类型
+        outputStream.write(commandType);
+
+        // 数据段
+        outputStream.write(data, 0, data.length);
+
+        // 校验码
+        int checksum = FRAME_HEADER;
+        checksum += dataLength + 7;
+        checksum += ackRequired;
+        checksum += messageSequence;
+        checksum += commandType;
+        for (byte b : data) {
+            checksum += b;
+        }
+        outputStream.write(checksum);
+
+        return outputStream.toByteArray();
+    }
+}

+ 546 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepService.java

@@ -0,0 +1,546 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.clj.fastble.utils.HexUtil;
+import com.wdkl.app.ncs.callingbed.BuildConfig;
+import com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil;
+import com.wdkl.app.ncs.callingbed.bt_gateway.NotificationUtil;
+import com.wdkl.app.ncs.callingbed.sleep.cdb.CbdBedDataParse;
+import com.wdkl.app.ncs.callingbed.sleep.client.WebSockeClient;
+import com.wdkl.ncs.android.middleware.common.Constant;
+import com.wdkl.ncs.android.middleware.common.MessageEvent;
+import org.altbeacon.beacon.BeaconConsumer;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import androidx.annotation.RequiresApi;
+import serialporttest.utils.SerialPortUtilCBDbed;
+import serialporttest.utils.SerialPortUtilSleep;
+import serialporttest.utils.SerialPortUtilSofa;
+
+
+public class SleepService extends Service implements BeaconConsumer, SleepSocketConnect.OnConnectStateListener, SleepSocketConnect.OnSocketReadListener , SerialPortUtilSleep.ISerialPortSleepData,
+        SerialPortUtilSofa.ISerialPortSofaData,SerialPortUtilCBDbed.ISerialPortBedData,
+        WebSockeClient.Clientback{
+
+    private static String TAG = SleepService.class.getSimpleName();
+
+    private SleepSocketConnectLine SleepSocketConnectLine;
+    private String ip = "47.115.176.250";
+    private int port = 3006;
+    private static SleepService bluetoothService;
+    public static boolean SleepconnectState = false;
+    public static String app_name = "APP";
+
+    NotificationUtil notificationUtil;
+
+    //是否第一次上电
+    private Boolean isSlepe = false;
+    //律动椅是否启动
+    private Boolean isDataReceived = false;
+//    //睡眠床垫是否有数据
+//    private Boolean Enabled = false;
+
+    //睡眠床垫全局计数
+    int Global_counting = 0;
+    //律动床垫全局计数
+    int Global_cbd_counting = 0;
+    //睡眠床垫全局计数
+    int Global_sofa_counting = 0;
+
+    private long lastDataTime = 0;
+    private Handler dataTimeoutHandler = new Handler();
+    private Runnable dataTimeoutChecker = new Runnable() {
+        @Override
+        public void run() {
+            if (System.currentTimeMillis() - lastDataTime > 5000) {
+                // 如果超过5秒没有接收到数据
+                isDataReceived = false;
+                Constant.CBD_ld_sofa_2 =false;
+                Log.d(TAG, "5秒内没有数据接收");
+            }
+            // 可以选择是否重复检查
+            // dataTimeoutHandler.postDelayed(this, 1000);
+        }
+    };
+
+    private SleepDataParse.OnDataCallback dataCallback;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new ServiceBinder();
+    }
+
+    public class ServiceBinder extends Binder {
+        public SleepService getService() {
+            return SleepService.this;
+        }
+
+        public void setData(String data) {
+            sendData(data);
+        }
+
+        public void setOnSignDataCallback(SleepDataParse.OnDataCallback callback) {
+            dataCallback = callback;
+        }
+    }
+
+
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        EventBus.getDefault().register(this);
+
+        //启动通知栏
+        notificationUtil = new NotificationUtil(this);
+        startForeground(notificationUtil.notificationId, notificationUtil.getBuilder().build());
+
+        if (BuildConfig.sleep_type.equals("3")){
+            Log.i(TAG, "连接ws---------------------");
+            BtPattern();
+        }else {
+            //0 4g 1 串口 2 蓝牙 3 wifi
+            SerialPattern();
+        }
+
+
+    }
+    private String data="";
+    private String old_sofa_data="";
+    private String old_bed_data="";
+    private String sofa_data="";
+    private String bed_data="";
+
+    //串口模式
+    private void SerialPattern(){
+        //打开串口
+        if (BuildConfig.sleep_type.equals("1")){
+            SerialPortUtilSleep.getInstance().openSerialPortLG();
+        }
+        //全部开启
+        if (BuildConfig.cbd_type.equals("1")){
+            SerialPortUtilSofa.getInstance().openSerialPort();
+            SerialPortUtilCBDbed.getInstance().openSerialPort();
+            SerialPortUtilSofa.getInstance().setOnSofaDataReceiveListener(this);
+            SerialPortUtilCBDbed.getInstance().setOnBedDataReceiveListener(this);
+        }else  if (BuildConfig.cbd_type.equals("2")){
+            //只开启 律动椅子
+            SerialPortUtilSofa.getInstance().openSerialPort();
+        }else  if (BuildConfig.cbd_type.equals("3")){
+            //只开启 律动床垫
+            SerialPortUtilCBDbed.getInstance().openSerialPort();
+        }
+        if (!BuildConfig.DEBUG) {
+            ip = Constant.SLEEP_TCP_SERVER_URL;
+            port = Constant.SLEEP_TCP_PORT;
+        }else {
+            ip = Constant.SLEEP_TCP_SERVER_URL_TXT;
+            port = Constant.SLEEP_TCP_PORT;
+        }
+
+        Log.e(TAG, "ip " + ip + " port " + port);
+
+        bluetoothService = this;
+        SleepSocketConnectLine = new SleepSocketConnectLine();
+        SleepSocketConnectLine.setIp(ip);
+        SleepSocketConnectLine.setPort(port);
+
+        SleepSocketConnectLine.setHeartbeatTime(1000 * 60);
+//        String data = String.format("0-%s:%s:%s",  NetFunctionConfig.getUser() + "", BaxcWebConfig.MACHINE_TYPE, Util.getDeviceId(WebSocketClinetService2.this)); //机构ID:机器类型:机器码
+        final String data = "8204000000FF";
+        //ip = "47.115.176.250";
+        //port = 3006;
+        SleepSocketConnectLine.setHeartbeat(BluetoothUtil.hexStringToByteArray(data));//发送心跳数据
+        if (!SleepconnectState  &&  Constant.CUSTOM_ID != -1){
+            SleepSocketConnectLine.start();
+            SleepSocketConnectLine.setOnConnectStateListener(this);//监听是否在线
+            SleepSocketConnectLine.setOnSocketReadListener(this);  //监听返回数据
+            SerialPortUtilSleep.getInstance().setOnSleepDataReceiveListener(this);
+        }
+    }
+    private  WebSockeClient webSockeClient;
+
+    //蓝牙模式
+    private void BtPattern(){
+        String baseurl = "ws://api.base.wdklian.com/sleep_report/monitor";
+        webSockeClient = new WebSockeClient(baseurl);
+        webSockeClient.setJClientback(this);
+        webSockeClient.connect();
+    }
+
+    @Override
+    public void onMessage(String message) {
+        //这里去处理波形的信息
+        //心率 //呼吸 //状态 //电池电量
+        String substring = message.substring(22, 30);
+        //波形
+        String heartRate = message.substring(34);
+//        Log.d(TAG, "睡眠数据: " + substring);
+//        Log.d(TAG, "波形数据: " + heartRate);
+        EventBus.getDefault().post(new MessageEvent("sleep", Constant.EVENT_SLEEP_DATA,substring,null));
+        EventBus.getDefault().post(new MessageEvent("sleep", Constant.EVENT_SLEEP_TYPE,null,heartRate));
+
+
+    }
+
+    @Override
+    public void onError(int errorCode, String error) {
+
+    }
+    /**
+     * 律动椅子
+     * */
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    @Override
+    public void onSerialSofaData(byte[] buffer, int size) {
+        Constant.CBD_ld_sofa =true;
+        if (buffer == null || !isSlepe) {
+            return;
+        }
+        isDataReceived = true;
+        // 更新接收时间和状态
+        lastDataTime = System.currentTimeMillis();
+        dataTimeoutHandler.removeCallbacks(dataTimeoutChecker);
+        dataTimeoutHandler.postDelayed(dataTimeoutChecker, 5000);
+        sofa_data=HexUtil.formatHexString(buffer, false);
+        Log.d(TAG, "律动椅子串口数据: " + sofa_data);
+        if (!SleepconnectState ){
+            Global_sofa_counting = 0;
+            return;
+        }
+        Global_sofa_counting+=1;
+        if (!sofa_data.substring(0, 2).equalsIgnoreCase("FF")) {
+            return;
+        }
+        byte[]   signData = CbdBedDataParse.parseValue(sofa_data,Global_counting);
+        if (signData.equals(""))return;
+        Constant.CBD_ld_sofa_2 =true;
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (SleepSocketConnectLine != null) {
+                        Thread.sleep(200);
+                        SleepSocketConnectLine.send(signData);
+                    }
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+
+    }
+
+    /**
+     * 律动床垫
+     * */
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    @Override
+    public void onSerialBedData(byte[] buffer, int size) {
+        Constant.CBD_ld_bed =true;
+        if (buffer == null || !isSlepe) {
+            Constant.CBD_ld_bed_2 =false;
+            return;
+        }
+        bed_data=HexUtil.formatHexString(buffer, false);
+        Log.d(TAG, "律动床垫串口数据: " + bed_data);
+        if (!SleepconnectState ){
+            Global_cbd_counting = 0;
+            return;
+        }
+        Constant.CBD_ld_bed_2 =true;
+        //每秒上传
+        byte[]   signData = CbdBedDataParse.parseValue2(bed_data,Global_counting);
+        if (signData.equals(""))return;
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (SleepSocketConnectLine != null) {
+                        Thread.sleep(100);
+                        SleepSocketConnectLine.send(signData);
+                    }
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+    }
+
+
+    /**
+     * 睡眠床垫
+     * */
+    @RequiresApi(api = Build.VERSION_CODES.O)
+    @Override
+    public void onSerialSleepData(byte[] buffer, int size) {
+//        Log.d(TAG, "原始数据: " + Arrays.toString(buffer));
+        Constant.CBD_ld_sleep =true;
+        if (buffer == null || isDataReceived) {
+            Constant.CBD_ld_sleep_2 =false;
+            return;
+        }
+        data = HexUtil.formatHexString(buffer, false);
+
+        if (data.substring(2, 4).equalsIgnoreCase("0f")) {
+            //波形
+            try {
+            //心率 //呼吸 //状态 //电池电量
+            String substring = data.substring(8, 28);
+            //波形
+            String heartRate = data.substring(32, 232);
+            //          Log.d(TAG, "睡眠数据: " + substring);
+            //          Log.d(TAG, "波形数据: " + heartRate);
+                EventBus.getDefault().post(new MessageEvent("sleep", Constant.EVENT_SLEEP_DATA,substring,null));
+                EventBus.getDefault().post(new MessageEvent("sleep", Constant.EVENT_SLEEP_TYPE,null,heartRate));
+
+            } catch (StringIndexOutOfBoundsException e) {
+            Log.e(TAG, "尝试访问的索引超出字符串长度范围", e);
+        }
+        }
+        if (!SleepconnectState){
+            return;
+        }
+        Global_counting+=1;
+        Log.d(TAG, "秒数数据: " + data);
+        if (!data.substring(0, 2).equalsIgnoreCase("cd")) {
+            return;
+        }
+        Constant.CBD_ld_sleep_2 =true;
+//        if (!isSlepe) {
+//            byte[]     signData = SleepDataParse.parseValue(data,Global_counting);
+//            Log.d(TAG, "发送登录数据1: " +  HexUtil.formatHexString(signData, false));
+//            if (signData.equals(""))return;
+//            new Thread(new Runnable() {
+//                @Override
+//                public void run() {
+//                    if (SleepSocketConnectLine != null) {
+//                        SleepSocketConnectLine.send(signData);
+//                    }
+//                }
+//            }).start();
+//        } else
+
+            if (data.substring(2, 4).equalsIgnoreCase("0f")) {
+//                 Log.d(TAG, "每秒串口数据: " + data);
+                //每秒上传
+                byte[]   signData = SleepDataParse.parseValue2(data,Global_counting);
+
+                if (signData.equals(""))return;
+
+                new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            if (SleepSocketConnectLine != null) {
+                                Thread.sleep(200);
+                                SleepSocketConnectLine.send(signData);
+                            }
+                        } catch (InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }).start();
+
+
+            }else if (data.substring(2, 4).equalsIgnoreCase("3e")){
+                //分层上传
+//                Log.d(TAG, "分层串口数据: " + data);
+                byte[]   signData = SleepDataParse.parseValue3(data,Global_counting);
+
+                if (signData.equals(""))return;
+                new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (SleepSocketConnectLine != null) {
+                            SleepSocketConnectLine.send(signData);
+                        }
+                    }
+                }).start();
+            }
+    }
+
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.e(TAG, "onStartCommand....");
+
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onBeaconServiceConnect() {
+
+    }
+
+    /**
+     * @param install
+     * @param connectState true为连接成功 false为断开连接
+     */
+    @Override
+    public void onConnectState(SleepSocketConnect install, boolean connectState) {
+        Log.e(TAG, "连接服务器是否成功 " + connectState);
+        this.SleepconnectState = connectState;
+        Constant.Sleep_TCP_CONNECTED=connectState;
+        EventBus.getDefault().post(new MessageEvent("CBD_TCP", Constant.EVENT_SLEEP_tcp));
+        try {
+            if (!Constant.Sleep_TCP_CONNECTED){
+                Log.e(TAG, "重新连接服务器 " + connectState);
+                SleepSocketConnectLine.start();
+                Global_counting = 0;
+                Global_cbd_counting= 0;
+                Global_sofa_counting= 0;
+                isSlepe =false;
+            }else {
+                Thread.sleep(2000);
+                //登录
+                    //第一次收到数据 登录
+                    String login_data = Constant.DEVICE_REGISTER_ID;
+                    byte[]   signData = SleepDataParse.parseValue5(login_data,Global_counting);
+                    Log.d(TAG, "发送登录数据2: " +  HexUtil.formatHexString(signData, false));
+                    if (signData.equals(""))return;
+                    new Thread(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (SleepSocketConnectLine != null) {
+                                SleepSocketConnectLine.send(signData);
+                            }
+                        }
+                    }).start();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 服务是否存活
+     *
+     * @return true: 存活
+     */
+    public static boolean isServiceRunning() {
+        return bluetoothService != null;
+    }
+
+    @Override
+    public void onSocketRead(SleepSocketConnect install, byte[] bytes) {
+        String data = bytesToHex(bytes);
+//        Log.e(TAG, "返回的数据data " + data);
+        String substring = data.substring(0, 2);
+        String substring2 = data.substring(8, 10);
+        if (substring.equals("82") && substring2.equals("03")){
+            isSlepe =true;
+            Log.e(TAG, "床垫——登录成功 " );
+        }
+        if ( substring2.equals("F1") ){
+            Log.e(TAG, "返回的律动床垫数据data " + data);
+            //f1 律动床垫 f2 律动椅子
+            String substring3 = data.substring(10, 12);
+            SerialPortUtilCBDbed.getInstance().sendCommand(substring3);
+        }
+        if ( substring2.equals("F2") ){
+            Log.e(TAG, "返回的律动椅数据data " + data);
+            //f1 律动床垫 f2 律动椅
+            String substring3 = data.substring(10, 12);
+            String substring4 = data.substring(12, 14);
+            SerialPortUtilSofa.getInstance().sendCommand(substring3,substring4);
+        }
+        if ( data.equals("82040101FFFF") ){
+            String bedStatus = getStatus(Constant.CBD_ld_bed);
+            String sofaStatus = getStatus(Constant.CBD_ld_sofa);
+            String sleepStatus = getStatus(Constant.CBD_ld_sleep);
+            String login_data = bedStatus+sofaStatus+sleepStatus;
+            byte[]   signData = SleepDataParse.parseValue6(login_data);
+            Log.d(TAG, "发送设备: " +  HexUtil.formatHexString(signData, false));
+            if (signData.equals(""))return;
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    if (SleepSocketConnectLine != null) {
+                        SleepSocketConnectLine.send(signData);
+                    }
+                }
+            }).start();
+        }
+
+
+    }
+    public String getStatus(boolean isActive) {
+        if (isActive ) {
+            return "01";
+        } else  {
+            return "00";
+        }
+    }
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder result = new StringBuilder();
+        for (byte b : bytes) {
+            result.append(String.format("%02X", b));
+        }
+        return result.toString();
+    }
+    /**
+     * 发送数据
+     *
+     * @param data
+     */
+    public void sendData(final String data) {
+        if (SleepSocketConnectLine != null) {
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    Log.e(TAG, "发送的数据 " + data);
+                    SleepSocketConnectLine.send(BluetoothUtil.hexStringToByteArray(data));
+                }
+            }).start();
+
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.e(TAG, "床垫服务关闭");
+        SerialPortUtilSleep.getInstance().closeSerialPort();
+        SerialPortUtilSofa.getInstance().closeSerialPort();
+        SerialPortUtilCBDbed.getInstance().closeSerialPort();
+        Global_counting = 0;
+        isSlepe =false;
+        EventBus.getDefault().unregister(this);
+        bluetoothService = null;
+        isDataReceived = false;
+        Constant.CBD_ld_sofa =false;
+        Constant.CBD_ld_bed =false;
+        Constant.CBD_ld_sleep =false;
+    }
+
+
+    @Subscribe(threadMode = ThreadMode.ASYNC)
+    public void onMoonEvent(MessageEvent messageEvent) {
+//        switch (messageEvent.getType()) {
+//            case Constant.EVENT_BLE_START:
+//                if (SleepSocketConnectLine != null) {
+//                    SleepSocketConnectLine.start();
+//                }
+//                break;
+//            case Constant.EVENT_BLE_STOP:
+//                if (SleepSocketConnectLine != null) {
+//                    SleepSocketConnectLine.release();
+//                }
+//                break;
+//        }
+    }
+}

+ 59 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSetwifiDataParse.java

@@ -0,0 +1,59 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+
+import com.clj.fastble.utils.HexUtil;
+import com.wdkl.app.ncs.callingbed.bt_gateway.BluetoothUtil;
+
+import java.io.ByteArrayOutputStream;
+
+public class SleepSetwifiDataParse {
+    public static final int FRAME_HEADER = 0xcd;
+    public static final int ACK_REQUIRED = 0x22;
+    public static final int NO_ACK_REQUIRED = 0x2c;
+    public static final int NO_ACK_REQUIRED2 = 0xff;
+    public static final int NO_ACK_type = 0x1f;
+
+
+    private byte[]  dataLength;
+    private  byte[]  name;
+    private  byte[]  Password;
+
+
+    public SleepSetwifiDataParse(byte[]  dataLength, String name, String Password) {
+        this.dataLength = dataLength;
+        this.name = HexUtil.hexStringToBytes(BluetoothUtil.strTo16(name ));
+        this.Password = HexUtil.hexStringToBytes(BluetoothUtil.strTo16(Password));
+
+    }
+
+    public byte[] toByteArray() {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        // 帧头
+        outputStream.write(FRAME_HEADER);
+
+        outputStream.write(NO_ACK_type);
+        // 长度
+        outputStream.write(dataLength, 0, dataLength.length);
+
+        outputStream.write(ACK_REQUIRED);
+
+        // wifi名称
+        outputStream.write(name, 0, name.length);
+
+        outputStream.write(ACK_REQUIRED);
+
+        outputStream.write(NO_ACK_REQUIRED);
+        outputStream.write(ACK_REQUIRED);
+        // wifi密码
+        outputStream.write(Password, 0, Password.length);
+        outputStream.write(ACK_REQUIRED);
+
+        outputStream.write(NO_ACK_REQUIRED2);
+        outputStream.write(NO_ACK_REQUIRED2);
+        outputStream.write(NO_ACK_REQUIRED2);
+        outputStream.write(NO_ACK_REQUIRED2);
+
+
+        return outputStream.toByteArray();
+    }
+}

+ 80 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSocketConnect.java

@@ -0,0 +1,80 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+
+/**
+ * socket连接类 断开连接可自动重连
+ * author 许柏胜
+ */
+public interface SleepSocketConnect {
+    int ERROR_START_FAIL = -1;
+    int ERROR_RELEASE_FAIL = -1;
+    int ERROR_SEND_NOT_CONNECT = -1; //未连接
+    int ERROR_SEND_IO_ERROR = -2; //IO异常
+
+    /**
+     * 开始连接
+     * @return 0为成功 非0为失败
+     */
+    int start();
+
+    /**
+     * 释放资源
+     * @return 0为成功 非0为失败
+     */
+    int release();
+
+    /**
+     * 发送数据
+     * @param datas
+     * @return 小于0为失败
+     */
+    int send(byte[] datas);
+
+    boolean isConnect();
+
+    void setIp(String ip);
+    void setPort(int port);
+    void setTag(String tag);
+
+    /**
+     * 设置心跳
+     * @param heartbeat
+     */
+    void setHeartbeat(byte[] heartbeat);
+
+    /**
+     * 设置心跳间隔时间
+     * @param heartbeatTime 默认为5秒
+     */
+    void setHeartbeatTime(long heartbeatTime);
+
+    long getHeartbeatTime();
+    byte[] getHeartbeat();
+    String getIp();
+    int getPort();
+    String getTag();
+
+
+    void setOnSocketReadListener(OnSocketReadListener onSocketReadListener);
+
+    void setOnConnectStateListener(OnConnectStateListener onConnectStateListener);
+
+    /**
+     * 读取回调
+     */
+    interface OnSocketReadListener{
+        void onSocketRead(SleepSocketConnect install, byte[] bytes);
+    }
+
+    /**
+     * 连接状态监听
+     */
+    interface OnConnectStateListener{
+        /**
+         *
+         * @param connectState true为连接成功 false为断开连接
+         */
+        void onConnectState(SleepSocketConnect install, boolean connectState);
+    }
+
+}

+ 417 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepSocketConnectLine.java

@@ -0,0 +1,417 @@
+package com.wdkl.app.ncs.callingbed.sleep;
+
+
+import android.util.Log;
+
+import com.clj.fastble.utils.HexUtil;
+import com.wdkl.app.ncs.callingbed.bt_gateway.SocketConnect;
+import com.wdkl.ncs.android.middleware.common.Constant;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * socket客户端 读取一行一行数据
+ * author 许柏胜
+ */
+public class SleepSocketConnectLine implements SleepSocketConnect {
+
+    private String ip;
+    private int port;
+    private String tag;
+    private byte[] heartbeat;
+    private long heartbeatTime = 5000;
+    private boolean isConnect;
+    private OnSocketReadListener onSocketReadListener;
+    private OnConnectStateListener onConnectStateListener;
+
+    private ConnectThread connectThread;
+//    private BufferedReader bufferedReader;
+    private DataInputStream dataInputStream;
+    private OutputStream outputStream;
+    private Socket socket;
+    private ReadThread readThread;
+    private HeartbeatThread heartbeatThread;
+
+    @Override
+    public int start() {
+        startConnectThread();
+        return 0;
+    }
+
+    @Override
+    public int release() {
+        stopConnectThread();
+        stopReadThread();
+        stopHeartbeatThread();
+//
+//        if (bufferedReader != null) {
+//            try {
+//                bufferedReader.close();
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//            bufferedReader = null;
+//        }
+
+        if (dataInputStream != null) {
+            try {
+                dataInputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            dataInputStream = null;
+        }
+
+        if (outputStream != null) {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            outputStream = null;
+        }
+
+        if (socket != null) {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            socket = null;
+        }
+
+        isConnect = false;
+
+        onConnectState(false);
+        return 0;
+    }
+
+    @Override
+    public int send(byte[] datas) {
+//         String data = HexUtil.formatHexString(datas, false);
+//        Log.d("tcp发送数据", "数据: " + data);
+            int ret = 0;
+            try {
+                ret = sendData(datas);
+                if(ret != 0){
+                    //重新连接
+                    log("发送失败,重新连接   "+ret);
+                    release();
+                }
+            } catch (Exception e) {
+                //连接失败重新连接
+                release();
+                e.printStackTrace();
+            }
+            return ret;
+
+    }
+
+    /**
+     * 连接线程
+     */
+    class ConnectThread extends Thread {
+        private boolean threadBool = false;
+        private int timeout = 5000;
+        private Socket socketTemp;
+        private boolean isConnected = false; //是否正在连接
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            isConnected = true;
+            while (threadBool) {
+                try {
+                    socketTemp = new Socket();
+                    socketTemp.connect(new InetSocketAddress(ip, port), timeout);
+                    isConnected = false;
+                    socket = socketTemp;
+//                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                    dataInputStream = new DataInputStream(socket.getInputStream());
+                    outputStream = socket.getOutputStream();
+                    startReadThread();
+                    startHeartbeatThread();
+                    log("连接成功");
+                    isConnect = true;
+                    onConnectState(true);
+                    stopThread();
+                    break;
+                } catch (IOException e) {
+                    //e.printStackTrace();
+                    log("连接失败重新连接:" + ip + ":" + port);
+                }
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            log("退出连接线程"+ip+":"+port);
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            Log.e("xxxx","");
+            if (isConnected) {
+                if (socketTemp != null) {
+                    try {
+                        socketTemp.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            interrupt();
+        }
+    }
+
+
+    private void log(String str) {
+        System.out.println(str);
+    }
+
+    private void startConnectThread() {
+        stopConnectThread();
+        connectThread = new ConnectThread();
+        connectThread.start();
+    }
+
+    private void stopConnectThread() {
+        if (connectThread != null) {
+            connectThread.stopThread();
+            connectThread = null;
+        }
+    }
+
+
+
+    void onConnectState(boolean connectState) {
+        if (onConnectStateListener != null) {
+            onConnectStateListener.onConnectState(this, connectState);
+        }
+    }
+
+    private void startHeartbeatThread() {
+        stopHeartbeatThread();
+        heartbeatThread = new HeartbeatThread();
+        heartbeatThread.start();
+    }
+
+    private void stopHeartbeatThread() {
+        if (heartbeatThread != null) {
+            heartbeatThread.stopThread();
+            heartbeatThread = null;
+        }
+    }
+
+    synchronized public int sendData(byte[] bytes){
+        int ret = 0;
+        if(bytes == null || bytes.length == 0) return ret;
+        try {
+            if (outputStream != null) {
+                outputStream.write(bytes);
+                outputStream.flush();
+                ret = 0;
+            }else ret = -1;
+        } catch (IOException e) {
+            e.printStackTrace();
+            ret = -2;
+        }
+        return ret;
+    }
+
+    /**
+     * 心跳线程
+     */
+    class HeartbeatThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+            threadBool = true;
+            while (threadBool) {
+                Log.e("sss777","心跳线程");
+                int ret = sendData(getHeartbeat());
+                if(ret != 0){
+                    stopThread();
+                    //重新连接
+                    log("发送失败,重新连接");
+                    release();
+                    startConnectThread();
+                    break;
+                }
+                try {
+                    Thread.sleep(heartbeatTime);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            log("退出心跳线程");
+        }
+
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+
+    private void startReadThread() {
+        stopReadThread();
+        readThread = new ReadThread();
+        readThread.start();
+    }
+
+    private void stopReadThread() {
+        if (readThread != null) {
+            readThread.stopThread();
+            readThread = null;
+        }
+    }
+    private boolean threadBool = false;
+    private boolean isReceivingPacket = false;
+    private ByteArrayOutputStream tempBuffer = new ByteArrayOutputStream();
+
+    /**
+     * 读取数据线程
+     */
+    class ReadThread extends Thread {
+
+        private boolean threadBool = false;
+
+        @Override
+        public void run() {
+            super.run();
+//            Log.e("sss","读取数据线程");
+            threadBool = true;
+            while (threadBool) {
+//                Log.e("sss111","读取数据线程");
+                    try {
+                        byte[] data = new byte[64];
+                        if (dataInputStream == null) {
+                            return;
+                        }
+                        int bytesRead = dataInputStream.read(data);
+
+                        if (bytesRead > 0) {
+                            if (data[0] == (byte) 0x82) {
+                                // 如果接收到新的数据包,清空临时缓冲区
+                                tempBuffer.reset();
+                                isReceivingPacket = true;
+                            }
+                            if (isReceivingPacket) {
+                                // 将数据写入临时缓冲区
+                                tempBuffer.write(data, 0, bytesRead);
+                                if (data[bytesRead - 1] == (byte) 0xFF) {
+                                    // 如果接收到数据包的结尾,处理完整的数据包
+                                    byte[] packet = tempBuffer.toByteArray();
+                                    disposeReadData(packet);
+                                    isReceivingPacket = false;
+                                }
+                            }
+                        }
+//                        Log.e("sss333","读取数据线程");
+                    } catch (Exception e) {
+//                        Log.e("sss44444","读取数据线程");
+                        e.printStackTrace();
+                        stopThread();
+                        break;
+
+                }
+            }
+//            log("退出读取数据线程");
+        }
+        public void stopThread() {
+            threadBool = false;
+            interrupt();
+        }
+    }
+
+    private void disposeReadData(byte[] bytes) {
+//        Log.e("sss666","获取的字节");
+        onSocketRead(bytes);
+    }
+    private void onSocketRead(byte[] bytes){
+//        Log.e("sss555","读取数据线程"+onSocketReadListener);
+        if(onSocketReadListener != null){
+            onSocketReadListener.onSocketRead(this, bytes);
+        }
+    }
+
+    @Override
+    public boolean isConnect() {
+        return isConnect;
+    }
+
+    @Override
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    @Override
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    @Override
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    @Override
+    public void setHeartbeat(byte[] heartbeat) {
+        this.heartbeat = heartbeat;
+    }
+
+    @Override
+    public void setHeartbeatTime(long heartbeatTime) {
+        this.heartbeatTime = heartbeatTime;
+    }
+
+    @Override
+    public long getHeartbeatTime() {
+        return heartbeatTime;
+    }
+
+    @Override
+    public byte[] getHeartbeat() {
+        return heartbeat;
+    }
+
+    @Override
+    public String getIp() {
+        return ip;
+    }
+
+    @Override
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public String getTag() {
+        return tag;
+    }
+
+    @Override
+    public void setOnSocketReadListener(OnSocketReadListener onSocketReadListener) {
+        this.onSocketReadListener = onSocketReadListener;
+    }
+
+    @Override
+    public void setOnConnectStateListener(OnConnectStateListener onConnectStateListener) {
+        this.onConnectStateListener = onConnectStateListener;
+    }
+}

+ 59 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/cdb/BedLoginDataParse.java

@@ -0,0 +1,59 @@
+package com.wdkl.app.ncs.callingbed.sleep.cdb;
+
+
+import java.io.ByteArrayOutputStream;
+
+public class BedLoginDataParse {
+    public static final int FRAME_HEADER = 0x82;
+    public static final int ACK_REQUIRED = 0x01;
+    public static final int NO_ACK_REQUIRED = 0x00;
+
+    private int dataLength;
+    private int ackRequired;
+    private int messageSequence;
+    private int commandType;
+    private byte[] data;
+
+    public BedLoginDataParse(int dataLength, int ackRequired, int messageSequence, int commandType, byte[] data) {
+        this.dataLength = dataLength;
+        this.ackRequired = ackRequired;
+        this.messageSequence = messageSequence;
+        this.commandType = commandType;
+        this.data = data;
+    }
+
+    public byte[] toByteArray() {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        // 帧头
+        outputStream.write(FRAME_HEADER);
+
+        // 长度
+        outputStream.write(dataLength);
+
+        // 应答要求
+        outputStream.write(ackRequired);
+
+        // 消息序号
+        outputStream.write(messageSequence);
+
+        // 命令类型
+        outputStream.write(commandType);
+
+        // 数据段
+        outputStream.write(data, 0, data.length);
+
+        // 校验码
+        int checksum = FRAME_HEADER;
+        checksum += dataLength + 15;
+        checksum += ackRequired;
+        checksum += messageSequence;
+        checksum += commandType;
+        for (byte b : data) {
+            checksum += b;
+        }
+        outputStream.write(checksum);
+
+        return outputStream.toByteArray();
+    }
+}

+ 0 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/cdb/CbdBedDataParse.java


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio