Quellcode durchsuchen

1护士主机增加nb设备界面,留言界面,喊话广播增加区域选择,广播模块tcp逻辑优化。

xunchuanzhi vor 1 Jahr
Ursprung
Commit
02d6bb9df9
67 geänderte Dateien mit 3535 neuen und 172 gelöschten Zeilen
  1. 6 0
      android_host/src/main/AndroidManifest.xml
  2. 309 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/activity/CreateMessageActivity.kt
  3. 153 134
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/activity/NurseHomeActivity.kt
  4. 63 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/CreatorAdapter.java
  5. 78 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/IotDeviceAdapter.kt
  6. 105 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/MessageAdapter.kt
  7. 3 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/di/NurseHomeComponent.kt
  8. 55 9
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/BroadcasthhFragment.kt
  9. 185 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/IotDeviceFragment.kt
  10. 260 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/MessageFragment.kt
  11. 0 3
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/SipCallFragment.kt
  12. 6 2
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/WorkFragment.kt
  13. 9 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/settingconfig/SettingConfig.java
  14. 80 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/ConfirmDialogHelper.java
  15. 95 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/MessageDialogHelper.java
  16. 21 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/SpeechUtil.java
  17. 3 0
      android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/TimeTransition.kt
  18. 5 0
      android_host/src/main/res/drawable/loading_bg_ripple_shape.xml
  19. BIN
      android_host/src/main/res/drawable/nb_iot2.png
  20. 5 0
      android_host/src/main/res/drawable/selector_record_btn.xml
  21. 11 11
      android_host/src/main/res/layout/activity_device_sys.xml
  22. 23 2
      android_host/src/main/res/layout/activity_new_nurse_home.xml
  23. 65 0
      android_host/src/main/res/layout/adapter_message_item.xml
  24. 25 0
      android_host/src/main/res/layout/adapter_nb_iot_device.xml
  25. 49 0
      android_host/src/main/res/layout/confirm_dialog.xml
  26. 23 0
      android_host/src/main/res/layout/creator_item.xml
  27. 143 0
      android_host/src/main/res/layout/fragment_message.xml
  28. 127 0
      android_host/src/main/res/layout/fragment_nb_iot_device.xml
  29. 202 0
      android_host/src/main/res/layout/message_create_dialog_activity.xml
  30. 46 0
      android_host/src/main/res/layout/message_dialog.xml
  31. 21 0
      android_host/src/main/res/values-es/strings.xml
  32. 20 0
      android_host/src/main/res/values-ru/strings.xml
  33. 36 0
      android_host/src/main/res/values-zh/strings.xml
  34. 23 0
      android_host/src/main/res/values/strings.xml
  35. 1 1
      common/build.gradle
  36. 5 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeHandle.kt
  37. 20 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/WidgetsUtil.java
  38. 85 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/BadgeRadioButton.java
  39. 318 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/BadgeUtil.java
  40. BIN
      common/src/main/res/drawable/toast_warn.png
  41. 32 0
      common/src/main/res/layout/view_toast_image2.xml
  42. 37 4
      middleware/src/main/code/com/wdkl/ncs/android/middleware/api/DeviceApi.kt
  43. 5 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/di/PresenterComponent.kt
  44. 132 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/helper/RecordHelper.java
  45. 30 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/nursehome/IotDeviceContract.kt
  46. 42 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/nursehome/MessageContract.kt
  47. 111 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/nursehome/IotDevicePresenter.kt
  48. 219 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/nursehome/MessagePresenter.kt
  49. 3 3
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/RemarkDO.java
  50. 45 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/RemarksVO.java
  51. 2 1
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/BroadcastUtil.java
  52. 41 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/MessageEvent.kt
  53. 43 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/ScreenUtils.java
  54. 52 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/StringUtil.java
  55. 2 1
      resource/build.gradle
  56. 6 0
      resource/src/main/res/drawable/ic_bc_play.xml
  57. 5 0
      resource/src/main/res/drawable/ic_message.xml
  58. 0 0
      resource/src/main/res/drawable/shape_button_bg2.xml
  59. 0 0
      resource/src/main/res/drawable/shape_papg_bg.xml
  60. BIN
      resource/src/main/res/mipmap-mdpi/ic_note_message.png
  61. BIN
      resource/src/main/res/mipmap-mdpi/ic_record_normal.png
  62. BIN
      resource/src/main/res/mipmap-mdpi/ic_record_press.png
  63. 12 0
      resource/src/main/res/values-es/strings.xml
  64. 12 0
      resource/src/main/res/values-ru/strings.xml
  65. 3 0
      resource/src/main/res/values-zh/strings.xml
  66. 12 1
      resource/src/main/res/values/strings.xml
  67. 5 0
      resource/src/main/res/values/styles.xml

+ 6 - 0
android_host/src/main/AndroidManifest.xml

@@ -126,6 +126,12 @@
         <activity android:name=".activity.SipTestActivity" />
         <activity android:name=".activity.CallActivity" />
 
+        <activity android:name=".activity.CreateMessageActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
+            android:windowSoftInputMode="stateAlwaysHidden"
+            android:screenOrientation="landscape"
+            android:launchMode="singleInstance"/>
+
         <service
             android:name=".service.WdklSipService"
             android:label="@string/app_name" />

+ 309 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/activity/CreateMessageActivity.kt

@@ -0,0 +1,309 @@
+package com.wdkl.ncs.android.component.nursehome.activity
+
+import android.annotation.SuppressLint
+import android.graphics.Color
+import android.os.Bundle
+import android.os.SystemClock
+import android.text.TextUtils
+import android.util.Log
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.AdapterView
+import com.enation.javashop.net.engine.model.NetState
+import com.wdkl.ncs.android.component.nursehome.R
+import com.wdkl.ncs.android.component.nursehome.adapter.CreatorAdapter
+import com.wdkl.ncs.android.component.nursehome.databinding.MessageCreateDialogActivityBinding
+import com.wdkl.ncs.android.component.nursehome.launch.NurseHomeLaunch
+import com.wdkl.ncs.android.component.nursehome.settingconfig.SettingConfig
+import com.wdkl.ncs.android.component.nursehome.util.MediaPlayHelper
+import com.wdkl.ncs.android.component.nursehome.util.RingPlayHelper
+import com.wdkl.ncs.android.component.nursehome.util.SpeechUtil
+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.helper.RecordHelper
+import com.wdkl.ncs.android.middleware.logic.contract.nursehome.MessageContract
+import com.wdkl.ncs.android.middleware.logic.presenter.nursehome.MessagePresenter
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO
+import com.wdkl.ncs.android.middleware.model.dos.FrameDO
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO
+import com.wdkl.ncs.android.middleware.model.vo.RemarksVO
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import com.wdkl.ncs.android.middleware.utils.MessageEvent
+import com.wdkl.ncs.android.middleware.utils.ScreenUtils
+import kotlinx.android.synthetic.main.message_create_dialog_activity.*
+import okhttp3.MediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.io.File
+
+
+class CreateMessageActivity : BaseActivity<MessagePresenter, MessageCreateDialogActivityBinding>(), MessageContract.View {
+    val TAG = CreateMessageActivity::class.java.simpleName
+
+    private var messageType = 2  //1--用户备注,2--便签留言,3--语音留言
+    private var voiceMsgPath = ""
+
+    var downTime : Long = 0
+    var upTime : Long = 0
+    var downY : Float = 0f
+    var cancel : Boolean = false
+    var voiceFile : String? = null
+
+    var creatorAdapter: CreatorAdapter? = null
+    var selectClerk: String? = ""
+
+    override fun getLayId(): Int {
+        return R.layout.message_create_dialog_activity
+    }
+
+    override fun bindDagger() {
+        NurseHomeLaunch.component.inject(this)
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        setTheme(R.style.Theme_AppCompat_Translucent)
+
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun init() {
+        val lp: WindowManager.LayoutParams = window.attributes
+        lp.width = ScreenUtils.getScreenWidth(this)*2 / 3 // 屏幕宽度的一半
+        lp.height = ScreenUtils.getScreenHeight(this)*3 / 4 // 屏幕高度的一半
+        window.attributes = lp // 设置参数给window
+        setFinishOnTouchOutside(false)
+        RecordHelper.getInstance().init()
+
+        radio_text_msg.isChecked = true
+        if (group_message_type.checkedRadioButtonId == R.id.radio_voice_msg) {
+            //语音
+            messageType = 3
+            edit_text_message.visibility = View.GONE
+            ll_voice_message.visibility = View.VISIBLE
+        } else {
+            //文本
+            messageType = 2
+            edit_text_message.visibility = View.VISIBLE
+            ll_voice_message.visibility = View.GONE
+        }
+
+        if (Constant.PART_ID != -1) {
+            presenter.loadClerks(Constant.PART_ID)
+        }
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    override fun bindEvent() {
+        btn_add_cancel.setOnClickListener {
+            finish()
+        }
+
+        btn_add_save.setOnClickListener {
+            val remark = RemarkDO()
+            remark.partId = Constant.PART_ID
+            remark.type = messageType
+            if (TextUtils.isEmpty(selectClerk)) {
+                showMessage(R.string.str_invalid_creator_name)
+                return@setOnClickListener
+            } else {
+                remark.createName = selectClerk
+            }
+            if (messageType == 2) {
+                if (TextUtils.isEmpty(edit_text_message.text)) {
+                    showMessage(R.string.str_message_content_error)
+                    return@setOnClickListener
+                } else {
+                    remark.content = edit_text_message.text.toString()
+                }
+            } else if (messageType == 3) {
+                if (TextUtils.isEmpty(voiceMsgPath)) {
+                    showMessage(R.string.str_voice_message_invalid)
+                    return@setOnClickListener
+                } else {
+                    remark.content = getString(R.string.voice_message)
+                    remark.filePath = voiceMsgPath
+                }
+            }
+
+            presenter.addNewMessage(remark)
+        }
+
+        ll_message_view.setOnClickListener {
+            //收起软键盘
+            CommonUtils.hideInputKeyboard(activity.window.decorView.windowToken)
+        }
+
+        group_message_type.setOnCheckedChangeListener { group, checkedId ->
+            //收起软键盘
+            CommonUtils.hideInputKeyboard(activity.window.decorView.windowToken)
+
+            if (checkedId == R.id.radio_voice_msg) {
+                //语音
+                messageType = 3
+                edit_text_message.visibility = View.GONE
+                ll_voice_message.visibility = View.VISIBLE
+            } else {
+                //文本
+                messageType = 2
+                edit_text_message.visibility = View.VISIBLE
+                ll_voice_message.visibility = View.GONE
+            }
+        }
+
+
+        //语音留言
+        btn_voice_record.setOnTouchListener { v, event ->
+            when(event.action) {
+                MotionEvent.ACTION_DOWN -> {
+                    cancel = false
+                    downTime = System.currentTimeMillis()
+                    downY = event.getY()
+
+                    //先停止其他语音或铃声
+                    RingPlayHelper.stopRingTone()
+                    SpeechUtil.getInstance().stopSpeak(true)
+                    MediaPlayHelper.getInstance().stopMusic()
+
+                    //开始录制语音消息
+                    RecordHelper.getInstance().startRecord()
+                    tv_voice_record.setText(R.string.str_voice_msg_btn_title)
+                    voice_record_timer.base = SystemClock.elapsedRealtime()
+                    voice_record_timer.start()
+                    voiceFile = RecordHelper.getInstance().audiofilePath
+
+                    //按下时保持常亮
+                    //wakeLock.acquire()
+                }
+
+                MotionEvent.ACTION_MOVE -> {
+                    val moveY = event.getY()
+                    if (Math.abs(downY - moveY) > 100) {
+                        cancel = true
+                    }
+                }
+
+                MotionEvent.ACTION_UP -> {
+                    upTime = System.currentTimeMillis()
+                    RecordHelper.getInstance().stopRecord()
+                    tv_voice_record.setText(R.string.str_voice_msg_btn_text)
+                    voice_record_timer.base = SystemClock.elapsedRealtime()
+                    voice_record_timer.stop()
+
+                    if (Math.abs(upTime - downTime) <= 1000) {
+                        RecordHelper.getInstance().deleteAudioFile(voiceFile)
+                        showMessage(R.string.str_voice_msg_record_loss)
+                    } else if(cancel) {
+                        RecordHelper.getInstance().deleteAudioFile(voiceFile)
+                        showMessage(R.string.str_voice_msg_record_cancel)
+                    } else {
+                        //上传语音留言
+                        if (voiceFile != null) {
+                            val part = MultipartBody.Part.createFormData("file",
+                                voiceFile,
+                                RequestBody.create(MediaType.parse("multipart/form-data"), File(voiceFile!!))
+                            )
+                            presenter.uploadVoiceMsg(part)
+                        }
+                    }
+
+                    //松开时释放
+                    //wakeLock.release()
+                }
+            }
+
+            return@setOnTouchListener false
+        }
+    }
+
+    override fun destory() {
+        //退出时删除本地语音留言音频文件
+        if (!TextUtils.isEmpty(voiceFile)) {
+            RecordHelper.getInstance().deleteAudioFile(voiceFile)
+        }
+    }
+
+    override fun showMessages(data: ArrayList<RemarkDO>) {
+
+    }
+
+    override fun showPageMessages(data: RemarksVO) {
+
+    }
+
+    override fun resultAddMessage(remarkDO: RemarkDO) {
+        //添加便签留言返回的响应
+        Log.e(TAG, "message save success!")
+        showMessage(R.string.str_message_save_success)
+        setResult(11)
+        finish()
+    }
+
+    override fun resultDelMessage(data: String) {
+
+    }
+
+    override fun uploadResponse(result: String) {
+        voiceMsgPath = result
+        tv_voice_msg_state.setTextColor(Color.parseColor("#00ff00"))
+        tv_voice_msg_state.setText(R.string.str_record_message_success)
+        //上传完成后删除本地文件
+        RecordHelper.getInstance().deleteAudioFile(voiceFile)
+    }
+
+    override fun showClerks(data: ArrayList<ClerkDO>) {
+        if (data.size > 0) {
+            creatorAdapter = CreatorAdapter(activity, data)
+            spinner_creator.adapter = creatorAdapter
+            spinner_creator.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+                override fun onItemSelected(
+                    parent: AdapterView<*>?,
+                    view: View,
+                    position: Int,
+                    id: Long
+                ) {
+                    selectClerk = data[position].clerkName
+                    Log.e(TAG, "select clerk name: " + selectClerk)
+                }
+
+                override fun onNothingSelected(parent: AdapterView<*>?) {}
+            }
+            spinner_creator.setSelection(0)
+        }
+    }
+
+    override fun onError(message: String, type: Int) {
+
+    }
+
+    override fun complete(message: String, type: Int) {
+
+    }
+
+    override fun start() {
+
+    }
+
+    override fun onStart() {
+        EventBus.getDefault().register(this)
+        super.onStart()
+    }
+
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
+    override fun networkMonitor(state: NetState) {
+
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+    }
+
+}

+ 153 - 134
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/activity/NurseHomeActivity.kt

@@ -37,6 +37,7 @@ import com.wdkl.ncs.android.component.nursehome.visit.frgment.VisitCallFragment
 import com.wdkl.ncs.android.component.nursehome.visit.frgment.VisitMainFragment
 import com.wdkl.ncs.android.component.nursehome.visit.frgment.VisitSetFragment
 import com.wdkl.ncs.android.component.nursehome.hardware.HardWareFactroy
+import com.wdkl.ncs.android.component.nursehome.helper.SoundPoolManager
 import com.wdkl.ncs.android.component.nursehome.launch.NurseHomeLaunch
 import com.wdkl.ncs.android.component.nursehome.led.LedItem
 import com.wdkl.ncs.android.component.nursehome.led.LedManagerUtils
@@ -465,6 +466,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
         batteryInterFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
         //batteryInterFilter.addAction(Intent.ACTION_POWER_CONNECTED)
         //batteryInterFilter.addAction(Intent.ACTION_POWER_DISCONNECTED)
+
         batteryBroadcastReceiver = BatteryBroadcastReceiver(battery_state_img)
         registerReceiver(batteryBroadcastReceiver, batteryInterFilter)
     }
@@ -610,6 +612,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
 //        }
 
         main_rl_3.setOnClickListener(this)
+        nb_device_radio_bt.setOnClickListener(this)
     }
     /**
      *页面销毁回调
@@ -957,7 +960,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
         if (removeRight) {
             removeRightFragment()
         } else {
-            showMiddleFragment(FramePartFragment())
+            showMiddleFragment(FramePartFragment(),true)
         }
     }
 
@@ -973,38 +976,41 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
            }
            //首页
            R.id.menu_home -> {
-               showMiddleFragment(FramePartFragment())
+               showMiddleFragment(FramePartFragment(),true)
            }
            R.id.menu_ward -> {
-               showMiddleFragment(SickbedFragment())
+               showMiddleFragment(SickbedFragment(),true)
            }
            //广播
            R.id.menu_broadcasting -> {
 
-               showMiddleFragment(BroadcastNewFragment())
+               showMiddleFragment(BroadcastNewFragment(),true)
            }
 
            R.id.menu_doctor -> {
-               showMiddleFragment(DoctorHostFragment())
+               showMiddleFragment(DoctorHostFragment(),true)
            }
 
            R.id.menu_moving -> {
-               showMiddleFragment(NurseMoveFragment())
+               showMiddleFragment(NurseMoveFragment(),true)
            }
 
            R.id.menu_others -> {
-               showMiddleFragment(OtherHostFragment())
+               showMiddleFragment(OtherHostFragment(),true)
            }
 
            R.id.menu_more -> {
-               showMiddleFragment(WorkFragment())
+               showMiddleFragment(WorkFragment(),true)
            }
            R.id.menu_hosting -> {
-               showMiddleFragment(TrustManagementFragment())
+               showMiddleFragment(TrustManagementFragment(),true)
+           }
+           R.id.nb_device_radio_bt -> {
+               showMiddleFragment(IotDeviceFragment(),true)
            }
 
            R.id.menu_led -> {
-               showMiddleFragment(VisitMainFragment())
+               showMiddleFragment(VisitMainFragment(),true)
                redDot.visibility = View.GONE
            }
 
@@ -1021,11 +1027,11 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
     }
 
     //显示中间主界面
-    fun showMiddleFragment(fragment: Fragment) {
+    fun showMiddleFragment(fragment: Fragment, boolean: Boolean) {
         supportFragmentManager.inTransaction {
             remove(currentFragment!!)
             currentFragment = fragment
-            updateLeftBtState()
+            updateLeftBtState(boolean)
             add(R.id.host_main_frame, fragment)
         }
     }
@@ -1080,8 +1086,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                 .commitAllowingStateLoss()
             skyCallFragment = null
         }
-        //call_frame_new.bringToFront()
-
+//        call_frame_new.bringToFront()
         skyCallFragment = fragment
         supportFragmentManager.beginTransaction()
             .setCustomAnimations(R.anim.slide_down_in, R.anim.slide_up_out)
@@ -1302,12 +1307,11 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                 hookonTime = System.currentTimeMillis()
             } else if (intent.action == Constant.HOOK_OFF) {
                 Log.e(TAG, "手柄拿起 ")
-                EventBus.getDefault().post(MessageEvent(false, Constant.EVENT_TOGGLE_SPEAKER))
                 if (System.currentTimeMillis() - hookoffTime > 2000) {
                     Constant.hookOn = false
+                    EventBus.getDefault().post(MessageEvent(false, Constant.EVENT_TOGGLE_SPEAKER))
                     VoiceManagerUtil.switchAudioMode(activity, false)
                     VoiceManagerUtil.setCallVoice(activity, SettingConfig.getHostCallVolume(activity))
-
                     if (Constant.CALL_STATE == Constant.CALL_STANDBY) {
                         //不是呼出也不是通话状态则接听电话
                         EventBus.getDefault().post(MessageEvent("hookoff", Constant.EVENT_HOOK_OFF))
@@ -1326,12 +1330,11 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
         Log.d(TAG, "keyDown ====> keyCode: $keyCode, action: ${event?.action}")
         if (keyCode == 135 || keyCode == 139) {
             //手柄拿起
-            Constant.hookOn = false
-            EventBus.getDefault().post(MessageEvent(false, Constant.EVENT_TOGGLE_SPEAKER))
             if (System.currentTimeMillis() - hookoffTime > 2000) {
+                Constant.hookOn = false
+                EventBus.getDefault().post(MessageEvent(false, Constant.EVENT_TOGGLE_SPEAKER))
                 VoiceManagerUtil.switchAudioMode(activity, false)
                 VoiceManagerUtil.setCallVoice(activity, SettingConfig.getHostCallVolume(activity))
-
                 if (Constant.CALL_STATE == Constant.CALL_STANDBY) {
                     //不是呼出也不是通话状态则接听电话
                     EventBus.getDefault().post(MessageEvent("hookoff", Constant.EVENT_HOOK_OFF))
@@ -1469,106 +1472,121 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
             //view_title_layout_tv_point.setBackgroundResource(R.mipmap.sip_h)
         }
     }
-    private fun updateLeftBtState() {
-        menu_home.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_home.setTextColor(getResources().getColor(R.color.white))
+    private fun updateLeftBtState(isbg :Boolean) {
 
-        menu_broadcasting.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_broadcasting.setTextColor(getResources().getColor(R.color.white))
+        if(isbg){
+            menu_home.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_home.setTextColor(getResources().getColor(R.color.white))
 
-        menu_doctor.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_doctor.setTextColor(getResources().getColor(R.color.white))
+            menu_broadcasting.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_broadcasting.setTextColor(getResources().getColor(R.color.white))
 
-        menu_ward.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_ward.setTextColor(getResources().getColor(R.color.white))
+            menu_doctor.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_doctor.setTextColor(getResources().getColor(R.color.white))
 
-        menu_ward_disease.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_ward_disease.setTextColor(getResources().getColor(R.color.white))
+            menu_ward.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_ward.setTextColor(getResources().getColor(R.color.white))
 
-        menu_moving.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_moving.setTextColor(getResources().getColor(R.color.white))
+            menu_ward_disease.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_ward_disease.setTextColor(getResources().getColor(R.color.white))
 
-        menu_others.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_others.setTextColor(getResources().getColor(R.color.white))
+            menu_moving.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_moving.setTextColor(getResources().getColor(R.color.white))
 
-        menu_settings.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_settings.setTextColor(getResources().getColor(R.color.white))
+            menu_others.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_others.setTextColor(getResources().getColor(R.color.white))
 
-        menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_led.setTextColor(getResources().getColor(R.color.white))
+            menu_settings.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_settings.setTextColor(getResources().getColor(R.color.white))
 
-        menu_more.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_more.setTextColor(getResources().getColor(R.color.white))
+            menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_led.setTextColor(getResources().getColor(R.color.white))
 
-        menu_hosting.setBackgroundResource(R.drawable.shape_main_bt_bg)
-        menu_hosting.setTextColor(getResources().getColor(R.color.white))
-        group_menus.clearCheck()
-        // 判断当前显示的Fragment是哪个
-        when (currentFragment) {
-            is FramePartFragment -> {
-                //首页
-                main_rl_3.visibility = View.VISIBLE
-                menu_home.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_home.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is DoctorHostFragment -> {
-                //医生
-                menu_doctor.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_doctor.setTextColor(getResources().getColor(R.color.delete_text_color))
-            }
-            is BroadcastNewFragment -> {
-                //广播
-                menu_broadcasting.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_broadcasting.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is BedsInTheWardFragment -> {
-                //病区
-                menu_ward_disease.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_ward_disease.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is SickbedFragment -> {
-                //病床
-                menu_ward.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_ward.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is SystemSettingsFragment -> {
-                //设置
-                menu_settings.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_settings.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is TrustManagementFragment -> {
-                //托管
-                menu_hosting.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_hosting.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is NurseMoveFragment -> {
-                //移动
-                menu_moving.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_moving.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
+            menu_more.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_more.setTextColor(getResources().getColor(R.color.white))
 
-            is OtherHostFragment -> {
-                //其他
-                menu_others.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_others.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is LedSettingsFragment -> {
-                //led
-                menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_led.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is WorkFragment -> {
-                //更多
-                menu_more.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_more.setTextColor(getResources().getColor(R.color.delete_text_color));
-            }
-            is VisitMainFragment -> {
-                //探视
-                menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg2)
-                menu_led.setTextColor(getResources().getColor(R.color.delete_text_color));
+            menu_hosting.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            menu_hosting.setTextColor(getResources().getColor(R.color.white))
+
+            nb_device_radio_bt.setBackgroundResource(R.drawable.shape_main_bt_bg)
+            nb_device_radio_bt.setTextColor(getResources().getColor(R.color.white))
+
+            group_menus.clearCheck()
+            // 判断当前显示的Fragment是哪个
+            when (currentFragment) {
+                is FramePartFragment -> {
+                    //首页
+                    main_rl_3.visibility = View.VISIBLE
+                    menu_home.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_home.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is DoctorHostFragment -> {
+                    //医生
+                    menu_doctor.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_doctor.setTextColor(getResources().getColor(R.color.delete_text_color))
+                }
+                is BroadcastNewFragment -> {
+                    //广播
+                    menu_broadcasting.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_broadcasting.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is BedsInTheWardFragment -> {
+                    //病区
+                    menu_ward_disease.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_ward_disease.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is SickbedFragment -> {
+                    //病床
+                    menu_ward.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_ward.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is SystemSettingsFragment -> {
+                    //设置
+                    menu_settings.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_settings.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is TrustManagementFragment -> {
+                    //托管
+                    menu_hosting.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_hosting.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is NurseMoveFragment -> {
+                    //移动
+                    menu_moving.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_moving.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+
+                is OtherHostFragment -> {
+                    //其他
+                    menu_others.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_others.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+//            is LedSettingsFragment -> {
+//                //led
+//                menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+//                menu_led.setTextColor(getResources().getColor(R.color.delete_text_color));
+//            }
+                is WorkFragment -> {
+                    //更多
+                    menu_more.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_more.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is VisitMainFragment -> {
+                    //探视
+                    menu_led.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    menu_led.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
+                is IotDeviceFragment -> {
+                    //nb设备
+                    nb_device_radio_bt.setBackgroundResource(R.drawable.shape_main_bt_bg2)
+                    nb_device_radio_bt.setTextColor(getResources().getColor(R.color.delete_text_color));
+                }
             }
         }
 
+
+
+
     }
 
     override fun onBackPressed() {
@@ -2110,24 +2128,21 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                         EventBus.getDefault().post(MessageEvent(0, Constant.EVENT_REFRESH_CALL_LIST))
                     } else if (tcpModel.action == TcpAction.DataAction.REMIND) {
                         //如果当前不在NB-IoT设备界面则提醒
-//                        nb_device_radio_bt.update(0)
-//                        WidgetsUtil.showToastWithImage(getString(R.string.iot_device_warning), 360f, 320f, R.drawable.toast_warn)
-//
-//                        if (!SettingConfig.getNbVoiceWarning(activity)) {
-//                            return
-//                        }
-//
-//                        if (select_id != 11) {
-//                            if (SettingConfig.getTtsMode(activity) != SettingConfig.TTS_ON) {
-//                                SoundPoolManager.getInstance().playSound(5, 1.0f, 1.0f, 0)
-//                            } else {
-//                                if (tcpModel.data != null && tcpModel.data is String) {
-//                                    val text = tcpModel.data as String
-//                                    SpeechUtil.getInstance().stopSpeak(true)
-//                                    SpeechUtil.getInstance().speakSingleText(text)
-//                                }
-//                            }
-//                        }
+                        nb_device_radio_bt.update(0)
+                        WidgetsUtil.showToastWithImage(getString(R.string.iot_device_warning), 360f, 320f, R.drawable.toast_warn)
+
+                        if (!SettingConfig.getNbVoiceWarning(activity)) {
+                            return
+                        }
+                         if (SettingConfig.getTtsMode(activity) != SettingConfig.TTS_ON) {
+                                SoundPoolManager.getInstance().playSound(5, 1.0f, 1.0f, 0)
+                            } else {
+                                if (tcpModel.data != null && tcpModel.data is String) {
+                                    val text = tcpModel.data as String
+                                    SpeechUtil.getInstance().stopSpeak(true)
+                                    SpeechUtil.getInstance().speakSingleText(text)
+                                }
+                            }
                     }
                 } else if (tcpModel.type == TcpType.ENTRACEGUARD) {
                     if (tcpModel.action == TcpAction.EntraceGuardAction.STRANGER) {
@@ -2252,9 +2267,14 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                             //发送音频广播后返回的数据
                             val interactionVO = Gson().fromJson(tcpModel.data.toString(), InteractionVO::class.java)
                             val json = JSON.parseObject(interactionVO.data.toString())
-                            val bid = json.getString("bId")
-                            addTobrIngList(interactionVO.id.toString(),bid)
-//                            Constant.bcInteractionId = interactionVO.id
+
+                            if(json.containsKey("bId")){
+                                var bid = json.getString("bId")
+                                addTobrIngList(interactionVO.id.toString(),bid)
+                            }else{
+                                //喊话广播
+                                Constant.bcInteractionId = interactionVO.id
+                            }
                         }
                     } else if (tcpModel.action == TcpAction.BroadcastAction.STOP) {
                         //广播结束
@@ -2412,7 +2432,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                 }
             }
             Constant.EVENT_r_br_set -> {
-                showMiddleFragment(BroadcastNewFragment())
+                showMiddleFragment(BroadcastNewFragment(),true)
 
             }
 
@@ -2430,7 +2450,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
             }
 
             Constant.EVENT_r_VISIT_th -> {
-                showMiddleFragment(VisitMainFragment())
+                showMiddleFragment(VisitMainFragment(),true)
 
             }
             Constant.EVENT_V_VISIT_th -> {
@@ -2533,7 +2553,6 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
 
     //手柄串口消息
     override fun forkSpringData(data: Int) {
-
         if (Constant.isText) {
             if (data == 1) {
                 EventBus.getDefault().post(MessageEvent("hook_off", Constant.EVENT_SERIAL_TEST))
@@ -2546,8 +2565,8 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
         if (data == 1) {
             //放下手柄
             SerialPortUtilHost.getInstance().setHandsFree(true)
-            SerialPortUtilHost.getInstance().setMIC(true)
-            //防止频繁按下
+            SerialPortUtilHost.getInstance().setMIC(true) //防止频繁按下
+            Constant.hookOn = true
             if (!Constant.hookOn && System.currentTimeMillis() - hookonTime > 1800) {
                 VoiceManagerUtil.setCallVoice(activity, SettingConfig.getHostHandsFreePlayVolume(this.activity))
                 if (Constant.CALL_STATE == Constant.CALL_OUTGOING) {
@@ -2563,13 +2582,13 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                 }
                 hookonTime = System.currentTimeMillis()
             }
-            Constant.hookOn = true
+
         } else if (data == 0) {
             //之前是放下状态,然后拿起手柄
             SerialPortUtilHost.getInstance().setHandsFree(false)
             SerialPortUtilHost.getInstance().setMIC(false)
+            Constant.hookOn = false
             EventBus.getDefault().post(MessageEvent(false, Constant.EVENT_TOGGLE_SPEAKER))
-
             if (Constant.hookOn && System.currentTimeMillis() - hookoffTime > 2000) {
                 VoiceManagerUtil.setCallVoice(activity, SettingConfig.getHostGamepadPlayVolume(this.activity))
                 if (Constant.CALL_STATE != Constant.CALL_CALLING && Constant.CALL_STATE != Constant.CALL_OUTGOING) {
@@ -2578,7 +2597,7 @@ class NurseHomeActivity  : BaseActivity<NurseHomeActivityPresenter, ActivityNewN
                 }
                 hookoffTime = System.currentTimeMillis()
             }
-            Constant.hookOn = false
+
         }
     }
 

+ 63 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/CreatorAdapter.java

@@ -0,0 +1,63 @@
+package com.wdkl.ncs.android.component.nursehome.adapter;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.wdkl.ncs.android.component.nursehome.R;
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO;
+
+import java.util.List;
+
+public class CreatorAdapter extends BaseAdapter {
+
+    private Context context;
+    private List<ClerkDO> clerkDOS;
+
+    public CreatorAdapter(Context context, List<ClerkDO> list) {
+        this.context = context;
+        this.clerkDOS = list;
+    }
+
+    @Override
+    public int getCount() {
+        return clerkDOS.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return clerkDOS.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+
+        ViewHolder holder = null;
+
+        if (convertView == null) {
+            convertView = View.inflate(context, R.layout.creator_item, null);
+
+            holder = new ViewHolder();
+            holder.tv = (TextView) convertView.findViewById(R.id.tv_frame_name);
+
+            convertView.setTag(holder);
+        } else {
+            holder = (ViewHolder) convertView.getTag();
+        }
+
+        holder.tv.setText(clerkDOS.get(position).getClerkName());
+
+        return convertView;
+    }
+
+    static class ViewHolder {
+        private TextView tv;
+    }
+}

+ 78 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/IotDeviceAdapter.kt

@@ -0,0 +1,78 @@
+package com.wdkl.ncs.android.component.nursehome.adapter
+
+import android.view.ViewGroup
+import com.alibaba.android.vlayout.LayoutHelper
+import com.alibaba.android.vlayout.layout.GridLayoutHelper
+import com.wdkl.ncs.android.component.nursehome.R
+import com.wdkl.ncs.android.component.nursehome.databinding.AdapterNbIotDeviceBinding
+import com.wdkl.ncs.android.lib.adapter.BaseDelegateAdapter
+import com.wdkl.ncs.android.lib.utils.BaseRecyclerViewHolder
+import com.wdkl.ncs.android.lib.utils.then
+import com.wdkl.ncs.android.middleware.model.vo.DeviceVO
+import com.wdkl.ncs.android.middleware.utils.StringUtil
+
+/**
+ * 其它主机适配器
+ */
+class IotDeviceAdapter (val data:ArrayList<DeviceVO>) : BaseDelegateAdapter<BaseRecyclerViewHolder<AdapterNbIotDeviceBinding>, DeviceVO>(){
+    /**
+     * 数据提供者
+     */
+    override fun dataProvider(): Any {
+        return data
+    }
+    /**
+     * Item坐标
+     */
+    override fun itemFilter(position: Int): Boolean {
+        return true
+    }
+    /**
+     * 获取Item总数
+     */
+    override fun getItemCount(): Int {
+        return data.size
+    }
+
+    /**
+     * 创建LayoutHelper
+     */
+    override fun onCreateLayoutHelper(): LayoutHelper {
+        return GridLayoutHelper(2).then {
+            self ->
+            /**取消自动填充*/
+            self.setAutoExpand(false)
+
+            /**设置左右间距*/
+            self.hGap = 10
+
+            /**设置上下间距*/
+            self.vGap = 10
+
+            /**设置Margin*/
+            self.setMargin(0,0,0,0)
+        }
+
+    }
+
+    /**
+     * 创建ViewHolder
+     */
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerViewHolder<AdapterNbIotDeviceBinding> {
+        return BaseRecyclerViewHolder.build(parent, R.layout.adapter_nb_iot_device)
+    }
+
+    /**
+     * 绑定数据
+     */
+    override fun onBindViewHolder(holder: BaseRecyclerViewHolder<AdapterNbIotDeviceBinding>, position: Int) {
+        holder?.bind { binding ->
+            val itemData = getItem(position)
+            binding.tvNbIotDevice.text = StringUtil.getResString(R.string.iot_device_name, itemData.name) + "\n" +
+                    StringUtil.getResString(R.string.iot_device_id, itemData.id) + "\n" +
+                    StringUtil.getResString(R.string.iot_device_mac, itemData.ethMac) + "\n" +
+                    StringUtil.getResString(R.string.iot_device_frame_name, itemData.fullName)
+        }
+    }
+
+}

+ 105 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/adapter/MessageAdapter.kt

@@ -0,0 +1,105 @@
+package com.wdkl.ncs.android.component.nursehome.adapter
+
+import android.graphics.Color
+import android.text.TextUtils
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import com.alibaba.android.vlayout.LayoutHelper
+import com.alibaba.android.vlayout.layout.GridLayoutHelper
+import com.wdkl.ncs.android.component.nursehome.R
+import com.wdkl.ncs.android.component.nursehome.databinding.AdapterMessageItemBinding
+import com.wdkl.ncs.android.component.nursehome.util.MediaPlayHelper
+import com.wdkl.ncs.android.component.nursehome.util.RingPlayHelper
+import com.wdkl.ncs.android.component.nursehome.util.SpeechUtil
+import com.wdkl.ncs.android.component.nursehome.util.TimeTransition
+import com.wdkl.ncs.android.lib.adapter.BaseDelegateAdapter
+import com.wdkl.ncs.android.lib.utils.BaseRecyclerViewHolder
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.lib.utils.then
+import com.wdkl.ncs.android.middleware.api.UrlManager
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO
+
+class MessageAdapter (val data:ArrayList<RemarkDO>) : BaseDelegateAdapter<BaseRecyclerViewHolder<AdapterMessageItemBinding>, RemarkDO>(){
+    /**
+     * 数据提供者
+     */
+    override fun dataProvider(): Any {
+        return data
+    }
+    /**
+     * Item坐标
+     */
+    override fun itemFilter(position: Int): Boolean {
+        return true
+    }
+    /**
+     * 获取Item总数
+     */
+    override fun getItemCount(): Int {
+        return data.size
+    }
+
+    /**
+     * 创建LayoutHelper
+     */
+    override fun onCreateLayoutHelper(): LayoutHelper {
+        return GridLayoutHelper(1).then {
+            self ->
+            /**取消自动填充*/
+            self.setAutoExpand(false)
+
+            /**设置左右间距*/
+            self.hGap = 10
+
+            /**设置上下间距*/
+            self.vGap = 16
+
+            /**设置Margin*/
+            self.setMargin(0,0,0,0)
+        }
+
+    }
+
+    /**
+     * 创建ViewHolder
+     */
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerViewHolder<AdapterMessageItemBinding> {
+        return BaseRecyclerViewHolder.build(parent, R.layout.adapter_message_item)
+    }
+
+    /**
+     * 绑定数据
+     */
+    override fun onBindViewHolder(holder: BaseRecyclerViewHolder<AdapterMessageItemBinding>, position: Int) {
+        holder?.bind { binding ->
+            val itemData = getItem(position)
+            if (position%2 == 1) {
+                binding.llMessage.setBackgroundColor(Color.parseColor("#8ef6e4"))
+            } else {
+                binding.llMessage.setBackgroundColor(Color.parseColor("#edb1f1"))
+            }
+
+            if (itemData.type == 3) {
+                binding.ivMessagePlay.setImageResource(R.drawable.ic_bc_play)
+            } else {
+                binding.ivMessagePlay.setImageResource(R.drawable.ic_message)
+            }
+
+            binding.tvMessageContent.text = itemData.content
+            binding.tvMessageCreator.text = itemData.createName
+            binding.tvMessageTime.text = TimeTransition.stampToYearDateTime(itemData.createTime * 1000)
+
+            binding.ivMessagePlay.setOnClickListener {
+                if (!TextUtils.isEmpty(itemData.filePath)) {
+                    RingPlayHelper.stopRingTone()
+                    SpeechUtil.getInstance().stopSpeak(true)
+                    showMessage("start play")
+                    MediaPlayHelper.getInstance().playUrlMusic(UrlManager.build().buyer + "/" + itemData.filePath, 1.0f, false)
+                }
+            }
+        }
+    }
+
+
+}

+ 3 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/di/NurseHomeComponent.kt

@@ -48,10 +48,13 @@ interface NurseHomeComponent{
     fun inject(activity: SignDataTableFragment)
     fun inject(activity: SignGraphOfCurveFragment)
     fun inject(activity: DeviceSystemActivity)
+    fun inject(activity: CreateMessageActivity)
 
     fun inject(fragment: VisitMainFragment)
     fun inject(fragment: VisitCallFragment)
     fun inject(fragment: VisitSetFragment)
+    fun inject(fragment: MessageFragment)
+    fun inject(fragment: IotDeviceFragment)
 
 
 }

+ 55 - 9
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/BroadcasthhFragment.kt

@@ -1,5 +1,7 @@
 package com.wdkl.ncs.android.component.nursehome.fragment
 
+import android.content.Context
+import android.media.AudioManager
 import android.util.Log
 import android.view.View
 import androidx.fragment.app.Fragment
@@ -27,7 +29,9 @@ import com.wdkl.ncs.android.middleware.model.vo.GroupBrVo
 import com.wdkl.ncs.android.middleware.tcp.TcpClient
 import com.wdkl.ncs.android.middleware.tcp.channel.BroadcastUtil
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpCallback
-
+import com.wdkl.ncs.android.middleware.utils.AudioRouteUtils
+import com.wdkl.ncs.android.middleware.utils.AudioRouteUtils.Companion.routeAudioToSpeaker
+import io.agora.base.internal.ContextUtils.getApplicationContext
 import kotlinx.android.synthetic.main.fragment_br_call.*
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
@@ -86,6 +90,7 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
         if (!SettingConfig.getSipEnabled(getActivity())){
             btn_record.visibility =View.VISIBLE
         }
+
     }
 
     /**
@@ -98,25 +103,30 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
             if (group_id.equals("")){
                 showMessage(R.string.br_message_9)
             }else{
+
                 if (SettingConfig.getSipEnabled(getActivity())){
                     if (Constant.bcStart) {
                         showMessage(R.string.broadcast_playing)
                     }else {
                         //先发起喊话广播请求,服务端返回端口再初始化
-                        val tcpModel = BroadcastUtil.startVoiceBroadcast(Constant.DEVICE_ID, group_id.joinToString(prefix = "[", postfix = "]"))  //给所有分机设备发
+                        val tcpModel = BroadcastUtil.startVoiceBroadcast(Constant.DEVICE_ID, group_id.joinToString(prefix = "[", postfix = "]"), "[]")  //给所有分机设备发
                         val transaction = object : TcpCallback(tcpModel.tid) {
                             override fun onSuccess(jsonObject: JSONObject) {
                                 try {
                                     val port = jsonObject.get(CALLBACK_DATA)
+                                    Log.d(TAG, "sipcall==> port: ${port.toString()}")
                                     //gstream初始化,指定服务器IP和音频端口
                                     core = WdklSipService.getCore()
+                                    val sipUri = "sip:$port"
                                     val addressToCall = core?.interpretUrl(port.toString())
                                     val params = core?.createCallParams(null)
                                     params?.isVideoEnabled = false
+
                                     if (addressToCall != null) {
                                         core?.inviteAddressWithParams(addressToCall, params!!)
                                     }
                                 } catch (ex: Exception) {
+                                    Log.d(TAG, "sipcall==> Exception: ${ex.toString()}")
                                     ex.printStackTrace()
                                 }
                             }
@@ -156,12 +166,11 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
                                     showMessage(R.string.broadcast_record_start)
                                     bcVoiceOn = true
                                 }
-
                                 MyGStreamManager.getInstance().play()
                             }
                         })
                         //先发起喊话广播请求,服务端返回端口再初始化
-                        val tcpModel = BroadcastUtil.startVoiceBroadcast(Constant.DEVICE_ID,  group_id.joinToString(prefix = "[", postfix = "]"))  //给所有分机设备发
+                        val tcpModel = BroadcastUtil.startVoiceBroadcast(Constant.DEVICE_ID, group_id.joinToString(prefix = "[", postfix = "]"), "[]")  //给所有分机设备发
                         val transaction = object : TcpCallback(tcpModel.tid) {
                             override fun onSuccess(jsonObject: JSONObject) {
                                 try {
@@ -207,7 +216,6 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
                         btn_record.setBackgroundResource(R.drawable.mic_off)
                         tv_record.setText(R.string.broadcast_record_stop)
                         bcVoiceOn = true
-
                         MyGStreamManager.getInstance().play()
                         my_voice_load_view.start()
                     } else {
@@ -297,7 +305,6 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
             // 未注册的逻辑处理
             EventBus.getDefault().register(this)
         }
-
     }
 
     override fun onStop() {
@@ -326,16 +333,55 @@ class BroadcasthhFragment : BaseFragment<BroadcasthhPresenter, FragmentBrCallBin
                     call_bt_call.visibility = View.GONE
                     call_bt_bt.visibility = View.VISIBLE
                     my_voice_load_view.start()
+                    toggleSpeaker(true)
+//                    speakerOn()
                     showMessage(R.string.broadcast_record_start)
                     bcVoiceOn = true
                 }
             }
+            Constant.EVENT_TOGGLE_SPEAKER -> {
+                if (Constant.hookOn) {
+                    //手柄放下
+                    toggleSpeaker(true)
+                } else {
+                    toggleSpeaker(false)
+                }
+            }
+        }
+    }
+    private fun toggleSpeaker(enable: Boolean) {
+        if ( core == null) {
+            core = WdklSipService.getCore()
+        }
+        if (enable) {
+            AudioRouteUtils.routeAudioToSpeaker(core!!)
+        } else {
+            AudioRouteUtils.routeAudioToEarpiece(core!!)
+        }
+    }
+    private var audioManager: AudioManager? = null
+
+    private fun speakerOn() {
+        // 适用于 Android 5.0 以上版本
+        audioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
+        audioManager?.apply {
+            mode = AudioManager.MODE_IN_CALL
+            // 设置音量,解决有些机型切换后没有声音或者声音突然变大的问题
+            setStreamVolume(
+                    AudioManager.STREAM_MUSIC,
+                    getStreamVolume(AudioManager.STREAM_MUSIC),
+                    AudioManager.FX_KEY_CLICK
+            )
+            isSpeakerphoneOn = true
+            core?.let {
+                routeAudioToSpeaker(it, null, false)
+            }
         }
     }
 
     override fun onItemClick(view: View, keyId: Int, ids: String) {
-        if (ids.isNotEmpty()){
-            group_id += ids
-        }
+        group_id = arrayOf(ids)
+        Log.d(TAG, "广播区域 ==> group_id: ${group_id.joinToString(", ")}")
+
     }
 }

+ 185 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/IotDeviceFragment.kt

@@ -0,0 +1,185 @@
+package com.wdkl.ncs.android.component.nursehome.fragment
+
+import android.view.View
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.alibaba.android.vlayout.VirtualLayoutManager
+import com.enation.javashop.net.engine.model.NetState
+import com.scwang.smartrefresh.layout.footer.ClassicsFooter
+import com.wdkl.ncs.android.component.nursehome.R
+import com.wdkl.ncs.android.component.nursehome.adapter.IotDeviceAdapter
+import com.wdkl.ncs.android.component.nursehome.databinding.FragmentNbIotDeviceBinding
+import com.wdkl.ncs.android.component.nursehome.launch.NurseHomeLaunch
+import com.wdkl.ncs.android.component.nursehome.settingconfig.SettingConfig
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.logic.contract.nursehome.IotDeviceContract
+import com.wdkl.ncs.android.middleware.logic.presenter.nursehome.IotDevicePresenter
+import com.wdkl.ncs.android.middleware.model.vo.DeviceVO
+import com.wdkl.ncs.android.middleware.utils.MessageEvent
+import kotlinx.android.synthetic.main.fragment_message.*
+import kotlinx.android.synthetic.main.fragment_nb_iot_device.*
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+/**
+ * NB IoT设备Fragment
+ */
+class IotDeviceFragment : BaseFragment<IotDevicePresenter, FragmentNbIotDeviceBinding>(), IotDeviceContract.View {
+    var TAG = IotDeviceFragment::class.java.getSimpleName()
+
+    private lateinit var virtualLayoutManager: VirtualLayoutManager
+    private lateinit var delegateAdapter: DelegateAdapter
+
+    private var iotDeviceAdapter: IotDeviceAdapter? = null
+    private var checkId = -1
+
+    /**
+     * 提供layoutID
+     */
+    override fun getLayId(): Int {
+        return R.layout.fragment_nb_iot_device
+    }
+
+    /**
+     *初始化依赖注入
+     */
+    override fun bindDagger() {
+        NurseHomeLaunch.component.inject(this)
+    }
+
+    /**
+     *初始化操作
+     */
+    override fun init() {
+
+        /**初始化LayoutMannager*/
+        virtualLayoutManager = VirtualLayoutManager(this.activity)
+        /**初始化适配器*/
+        delegateAdapter = DelegateAdapter(virtualLayoutManager)
+
+        iotDeviceAdapter = IotDeviceAdapter(ArrayList())
+        delegateAdapter.addAdapter(iotDeviceAdapter)
+        nb_iot_device_refresh.setRefreshFooter(ClassicsFooter(activity))
+
+        /**配置到RecycleView*/
+        rv_nb_iot_device.layoutManager = virtualLayoutManager
+        rv_nb_iot_device.adapter = delegateAdapter
+
+        if (SettingConfig.getNbVoiceWarning(activity)) {
+            rb_voice_warning_on.isChecked = true
+        } else {
+            rb_voice_warning_off.isChecked = true
+        }
+    }
+
+    /**
+     *绑定事件
+     */
+    override fun bindEvent() {
+        group_host.setOnCheckedChangeListener { group, checkedId ->
+            checkId = checkedId
+            loadData(checkedId)
+        }
+
+        rb_offline_device.isChecked = true
+
+        nb_iot_device_refresh.setOnRefreshListener {
+            loadData(checkId)
+        }
+
+        group_voice_warning.setOnCheckedChangeListener { group, checkedId ->
+            if (checkedId == R.id.rb_voice_warning_on) {
+                SettingConfig.setNbVoiceWarning(activity, true)
+            } else if (checkedId == R.id.rb_voice_warning_off) {
+                SettingConfig.setNbVoiceWarning(activity, false)
+            }
+        }
+    }
+
+    private fun loadData(id: Int) {
+        if (id == R.id.rb_offline_device) {
+            //离线NB设备
+            if (Constant.PART_ID != -1) {
+                presenter.loadOfflineDevice(Constant.PART_ID )
+            } else {
+                showMessage("partId is null")
+            }
+        } else if (id == R.id.rb_low_battery_device) {
+            //低电NB设备
+            if (Constant.PART_ID  != -1) {
+                presenter.loadLowBatteryDevice(Constant.PART_ID )
+            } else {
+                showMessage("partId is null")
+            }
+        }
+    }
+
+    /**
+     *页面销毁回调
+     */
+    override fun destory() {
+    }
+
+    /**
+     *显示数据
+     */
+    override fun showOfflineDevice(devices: ArrayList<DeviceVO>) {
+        nb_iot_device_refresh.finishRefresh()
+
+        iotDeviceAdapter!!.data.clear()
+        if (devices.size > 0) {
+            rv_nb_iot_emptyImageView.visibility= View.GONE
+            iotDeviceAdapter!!.data.addAll(devices)
+        }else{
+            rv_nb_iot_emptyImageView.visibility= View.VISIBLE
+        }
+        iotDeviceAdapter!!.notifyDataSetChanged()
+    }
+
+    override fun showLowBatteryDevice(devices: ArrayList<DeviceVO>) {
+        nb_iot_device_refresh.finishRefresh()
+
+        iotDeviceAdapter!!.data.clear()
+        if (devices.size > 0) {
+            rv_nb_iot_emptyImageView.visibility= View.GONE
+            iotDeviceAdapter!!.data.addAll(devices)
+        }else{
+            rv_nb_iot_emptyImageView.visibility= View.VISIBLE
+        }
+        iotDeviceAdapter!!.notifyDataSetChanged()
+    }
+
+    /**
+     *处理错误信息
+     */
+    override fun onError(message: String, type: Int) {
+        nb_iot_device_refresh.finishRefresh()
+
+        iotDeviceAdapter!!.data.clear()
+        iotDeviceAdapter!!.notifyDataSetChanged()
+        rv_nb_iot_emptyImageView.visibility= View.VISIBLE
+    }
+
+    /**
+     *耗时加载完成
+     */
+    override fun complete(message: String, type: Int) {
+    }
+
+    /**
+     *耗时加载开始
+     */
+    override fun start() {
+    }
+
+    /**
+     *处理网络状态
+     */
+    override fun networkMonitor(state: NetState) {
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+    }
+}

+ 260 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/MessageFragment.kt

@@ -0,0 +1,260 @@
+package com.wdkl.ncs.android.component.nursehome.fragment
+
+import android.content.Intent
+import android.util.Log
+import android.view.View
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.alibaba.android.vlayout.VirtualLayoutManager
+import com.enation.javashop.net.engine.model.NetState
+import com.scwang.smartrefresh.layout.footer.ClassicsFooter
+import com.wdkl.ncs.android.component.nursehome.R
+import com.wdkl.ncs.android.component.nursehome.activity.CreateMessageActivity
+import com.wdkl.ncs.android.component.nursehome.adapter.MessageAdapter
+import com.wdkl.ncs.android.component.nursehome.databinding.FragmentMessageBinding
+import com.wdkl.ncs.android.component.nursehome.launch.NurseHomeLaunch
+import com.wdkl.ncs.android.component.nursehome.util.ConfirmDialogHelper
+import com.wdkl.ncs.android.component.nursehome.util.MessageDialogHelper
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.base.BaseFragment
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.wdkl.ncs.android.middleware.common.Constant
+import com.wdkl.ncs.android.middleware.logic.contract.nursehome.MessageContract
+import com.wdkl.ncs.android.middleware.logic.presenter.nursehome.MessagePresenter
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO
+import com.wdkl.ncs.android.middleware.model.vo.RemarksVO
+import com.wdkl.ncs.android.middleware.utils.MessageEvent
+import kotlinx.android.synthetic.main.fragment_message.*
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+class MessageFragment : BaseFragment<MessagePresenter, FragmentMessageBinding>(), MessageContract.View {
+    var TAG = MessageFragment::class.java.getSimpleName()
+
+    private lateinit var virtualLayoutManager: VirtualLayoutManager
+    private lateinit var delegateAdapter: DelegateAdapter
+
+    private var messageAdapter: MessageAdapter? = null
+
+    private var pageNo = 1
+    private val pageSize = 4
+    private var totalSize = 0
+    private var totalPage = 1
+
+    /**
+     * 提供layoutID
+     */
+    override fun getLayId(): Int {
+        return R.layout.fragment_message
+    }
+
+    /**
+     *初始化依赖注入
+     */
+    override fun bindDagger() {
+        NurseHomeLaunch.component.inject(this)
+    }
+
+    /**
+     *初始化操作
+     */
+    override fun init() {
+        /**初始化LayoutMannager*/
+        virtualLayoutManager = VirtualLayoutManager(this.activity)
+        /**初始化适配器*/
+        delegateAdapter = DelegateAdapter(virtualLayoutManager)
+
+        messageAdapter = MessageAdapter(ArrayList())
+        delegateAdapter.addAdapter(messageAdapter)
+        message_refresh.setRefreshFooter(ClassicsFooter(activity))
+
+        /**配置到RecycleView*/
+        rv_messages.layoutManager = virtualLayoutManager
+        rv_messages.adapter = delegateAdapter
+
+        if (Constant.PART_ID != -1) {
+            presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+        }
+    }
+
+    /**
+     *绑定事件
+     */
+    override fun bindEvent() {
+        message_refresh.setOnRefreshListener {
+            if (Constant.PART_ID != -1) {
+                pageNo = 1
+                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+            }
+        }
+
+        message_refresh.setOnLoadMoreListener {
+            if (Constant.PART_ID != -1) {
+                pageNo += 1
+                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+            }
+        }
+
+        btn_add_message.setOnClickListener {
+            val intent = Intent(BaseApplication.appContext, CreateMessageActivity::class.java)
+            //startActivity(intent)
+            startActivityForResult(intent, 1)
+        }
+
+        messageAdapter?.setOnItemLongClickListener { data, position ->
+            //删除便签留言
+            ConfirmDialogHelper.showDialog(activity, getString(R.string.str_delete_tip)) {
+                presenter.deleteMessage(data.id)
+            }
+        }
+
+        messageAdapter?.setOnItemClickListener { data, position ->
+            //放大显示
+            MessageDialogHelper.showDialog(activity, data)
+        }
+
+//        btn_first_page.setOnClickListener {
+//            //第一页
+//            if (pageNo <= 1) {
+//                pageNo = 1
+//                showMessage(R.string.str_first_page)
+//            } else {
+//                pageNo = 1
+//                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+//            }
+//        }
+
+//        btn_last_page.setOnClickListener {
+//            //最后一页
+//            if (pageNo >= totalPage) {
+//                pageNo = totalPage
+//                showMessage(R.string.str_last_page)
+//            } else {
+//                pageNo = totalPage
+//                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+//            }
+//        }
+
+        btn_pre_page.setOnClickListener {
+            //上一页
+            if (pageNo <= 1) {
+                pageNo = 1
+                showMessage(R.string.str_first_page)
+            } else {
+                pageNo--
+                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+            }
+        }
+
+        btn_next_page.setOnClickListener {
+            //下一页
+            if (pageNo >= totalPage) {
+                pageNo = totalPage
+                showMessage(R.string.str_last_page)
+            } else {
+                pageNo++
+                presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+            }
+        }
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        //Log.e(TAG, "activity requestCode: $requestCode, resultCode: $resultCode")
+        if (requestCode == 1 && resultCode == 11) {
+            //添加留言成功,刷新列表
+            pageNo = 1
+            presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+        }
+    }
+
+    override fun destory() {
+    }
+
+    override fun showMessages(data: ArrayList<RemarkDO>) {
+
+    }
+
+    override fun showPageMessages(data: RemarksVO) {
+
+
+        totalSize = data.dataTotal
+        pageNo = data.pageNo
+        if (totalSize%pageSize == 0) {
+            totalPage = totalSize/pageSize
+        } else {
+            totalPage = totalSize/pageSize + 1
+        }
+        tv_page_no.text = "" + pageNo + "/" + totalPage
+
+        messageAdapter!!.data.clear()
+        if (data.data.size > 0) {
+
+            for (remark in data.data) {
+                //if (remark.type == 2 || remark.type == 3) {
+                //便签或语音留言
+                message_host_emptyImageView.visibility= View.GONE
+                messageAdapter!!.data.add(remark)
+                //}
+            }
+        }else{
+            message_host_emptyImageView.visibility= View.VISIBLE
+        }
+        messageAdapter!!.notifyDataSetChanged()
+    }
+
+    override fun resultAddMessage(remarkDO: RemarkDO) {
+
+    }
+
+    override fun resultDelMessage(data: String) {
+        Log.e(TAG, data)
+        showMessage(data)
+
+        //删除成功后刷新列表
+        pageNo = 1
+        presenter.loadMessageByPage(pageNo, pageSize, Constant.PART_ID)
+    }
+
+    override fun uploadResponse(result: String) {
+
+    }
+
+    override fun showClerks(data: ArrayList<ClerkDO>) {
+
+    }
+
+    /**
+     *处理错误信息
+     */
+    override fun onError(message: String, type: Int) {
+        message_refresh.finishRefresh()
+        message_refresh.finishLoadMore()
+        message_host_emptyImageView.visibility= View.VISIBLE
+
+        //messageAdapter!!.data.clear()
+        //messageAdapter!!.notifyDataSetChanged()
+    }
+
+    /**
+     *耗时加载完成
+     */
+    override fun complete(message: String, type: Int) {
+    }
+
+    /**
+     *耗时加载开始
+     */
+    override fun start() {
+    }
+
+    /**
+     *处理网络状态
+     */
+    override fun networkMonitor(state: NetState) {
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMoonEvent(messageEvent: MessageEvent) {
+    }
+}

+ 0 - 3
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/SipCallFragment.kt

@@ -207,7 +207,6 @@ class SipCallFragment: BaseCallFragment() {
         if (callEnded) {
             return
         }
-
         if (Constant.hookOn) {
             //免提
             toggleSpeaker(true)
@@ -247,7 +246,6 @@ class SipCallFragment: BaseCallFragment() {
         Log.e(TAG, ">>>>>>>>>>> call end !!!!!!!!!!!!!!!!!!")
         RingPlayHelper.stopRingTone()
         countDownTimer.cancel()
-
         synchronized(this) {
             if (callEnded) {
                 return
@@ -277,7 +275,6 @@ class SipCallFragment: BaseCallFragment() {
         if ( sipCore == null) {
             return
         }
-
         if (enable) {
             AudioRouteUtils.routeAudioToSpeaker(sipCore!!)
         } else {

+ 6 - 2
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/fragment/WorkFragment.kt

@@ -176,12 +176,16 @@ class WorkFragment : BaseFragment<BedNursingWorkFragmentPresenter, WorkLayBindin
                 }else if (allOrders.get(keyId).act_name.equals("LedSettingsFragment")){
                         //led设置
                     val mainActivity = activity as? NurseHomeActivity
-                    mainActivity?.showMiddleFragment(LedSettingsFragment())
+                    mainActivity?.showMiddleFragment(LedSettingsFragment(),false)
                 }
                 else if (allOrders.get(keyId).act_name.equals("SystemSettingsFragment")){
                     //科室设置
                     val mainActivity = activity as? NurseHomeActivity
-                    mainActivity?.showMiddleFragment(SystemSettingsFragment())
+                    mainActivity?.showMiddleFragment(SystemSettingsFragment(),false)
+                } else if (allOrders.get(keyId).act_name.equals("MessageFragment")){
+                    //留言
+                    val mainActivity = activity as? NurseHomeActivity
+                    mainActivity?.showMiddleFragment(MessageFragment(),false)
                 }
             }
         } catch (e: Exception) {

+ 9 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/settingconfig/SettingConfig.java

@@ -141,6 +141,7 @@ public class SettingConfig {
 
     private static final String KEY_SP_VOICE_NUMERIC = "KEY_SP_VOICE_NUMERIC";
     private static final String KEY_SP_RECORD_ENABLE = "KEY_SP_RECORD_ENABLE";
+    private static final String KEY_SP_NB_VOICE_WARNING = "KEY_SP_NB_VOICE_WARNING";
 
     //主机通话音量
     private static final String KEY_SP_HOST_CALL_VOLUME = "KEY_SP_HOST_CALL_VOLUME";
@@ -275,6 +276,14 @@ public class SettingConfig {
         getEditor(context).putBoolean(KEY_SP_RECORD_ENABLE, enable).apply();
     }
 
+    public static boolean getNbVoiceWarning(Context context) {
+        return getSP(context).getBoolean(KEY_SP_NB_VOICE_WARNING, true);
+    }
+
+    public static void setNbVoiceWarning(Context context, boolean enable) {
+        getEditor(context).putBoolean(KEY_SP_NB_VOICE_WARNING, enable).apply();
+    }
+
     /**
      * 获取播报次数
      *

+ 80 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/ConfirmDialogHelper.java

@@ -0,0 +1,80 @@
+package com.wdkl.ncs.android.component.nursehome.util;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+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.ncs.android.component.nursehome.R;
+
+public class ConfirmDialogHelper {
+
+    private static AlertDialog dialog;
+
+    public static void showDialog(final Activity activity, String titleText, MyListener clickListener) {
+        if (dialog != null) {
+            dialog.dismiss();
+            dialog = null;
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.confirm_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        TextView textView = contentView.findViewById(R.id.confirm_text);
+        Button buttonConfirm = contentView.findViewById(R.id.confirm_button);
+        Button buttonCancel = contentView.findViewById(R.id.cancel_button);
+
+        textView.setText(titleText);
+        buttonConfirm.setOnClickListener(v -> {
+            if (clickListener != null) {
+                clickListener.onConfirm();
+            }
+
+            if (dialog != null) {
+                dialog.dismiss();
+            }
+        });
+        buttonCancel.setOnClickListener(v -> {
+            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 = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+
+            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 interface MyListener{
+        void onConfirm();
+    }
+}

+ 95 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/MessageDialogHelper.java

@@ -0,0 +1,95 @@
+package com.wdkl.ncs.android.component.nursehome.util;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
+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.ImageButton;
+import android.widget.TextView;
+
+import com.wdkl.ncs.android.component.nursehome.R;
+import com.wdkl.ncs.android.middleware.api.UrlManager;
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO;
+
+import static com.wdkl.ncs.android.lib.utils.ExtendMethodsKt.showMessage;
+
+public class MessageDialogHelper {
+
+    private static AlertDialog dialog;
+
+    public static void showDialog(final Activity activity, final RemarkDO remarkDO) {
+        if (dialog != null) {
+            dialog.dismiss();
+            dialog = null;
+        }
+
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.message_dialog, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+        TextView textView = contentView.findViewById(R.id.message_text);
+        ImageButton play = contentView.findViewById(R.id.btn_message_play);
+        Button buttonCancel = contentView.findViewById(R.id.btn_cancel);
+        textView.setMovementMethod(ScrollingMovementMethod.getInstance());
+
+        if (remarkDO.getType() == 3) {
+            play.setVisibility(View.VISIBLE);
+        } else {
+            play.setVisibility(View.GONE);
+        }
+
+        textView.setText(remarkDO.getContent());
+        buttonCancel.setOnClickListener(v -> {
+            if (dialog != null) {
+                dialog.dismiss();
+            }
+        });
+
+        play.setOnClickListener(v -> {
+            if (!TextUtils.isEmpty(remarkDO.getFilePath())) {
+                RingPlayHelper.stopRingTone();
+                SpeechUtil.getInstance().stopSpeak(true);
+                showMessage("start play");
+                MediaPlayHelper.getInstance().playUrlMusic(UrlManager.Companion.build().getBuyer() + "/" + remarkDO.getFilePath(), 1.0f, false);
+            }
+        });
+
+        dialog = builder.create();
+        //dialog.setCanceledOnTouchOutside(false);
+        //dialog.setCancelable(false);
+        dialog.show();
+        dialog.setOnDismissListener(dialog -> {
+            if (remarkDO.getType() == 3 && MediaPlayHelper.getInstance().isMediaPlaying()) {
+                MediaPlayHelper.getInstance().stopMusic();
+            }
+        });
+
+        //设置dialog宽高及位置
+        try {
+            Window window = dialog.getWindow();
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+
+            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();
+        }
+    }
+}

+ 21 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/SpeechUtil.java

@@ -198,6 +198,27 @@ public class SpeechUtil {
         });
     }
 
+    public synchronized void speakSingleText(final String text) {
+        Log.d(TAG, "tts speak single text: " + text);
+        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) {
+                //语音播报完毕
+            }
+
+            @Override
+            public void onError(String utteranceId) {
+
+            }
+        });
+    }
+
     public void stopSpeak(boolean removeAll) {
         if (removeAll) {
             speechTextList.clear();

+ 3 - 0
android_host/src/main/java/com/wdkl/ncs/android/component/nursehome/util/TimeTransition.kt

@@ -22,6 +22,9 @@ object TimeTransition {
     fun stampToDateTime(s: Long):String{
         return TimeStampToTime(s, "MM-dd HH:mm:ss")
     }
+    fun stampToYearDateTime(s:Long):String{
+        return TimeStampToTime(s,"yyyy-MM-dd HH:mm:ss")
+    }
 
     /**
      * 时间戳转时间 不带时区

+ 5 - 0
android_host/src/main/res/drawable/loading_bg_ripple_shape.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#e7e7e7"/>
+</shape>

BIN
android_host/src/main/res/drawable/nb_iot2.png


+ 5 - 0
android_host/src/main/res/drawable/selector_record_btn.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@mipmap/ic_record_press" android:state_pressed="true"/>
+    <item android:drawable="@mipmap/ic_record_normal"/>
+</selector>

+ 11 - 11
android_host/src/main/res/layout/activity_device_sys.xml

@@ -149,6 +149,17 @@
 
                 </LinearLayout>
 
+                <RadioButton
+                    android:id="@+id/device_sys_radio_language_on"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:button="@null"
+                    android:drawableLeft="@drawable/radio_button_selector_bg2"
+                    android:drawablePadding="@dimen/d5"
+                    android:text="@string/str_yes"
+                    android:textColor="@drawable/radio_button_selector_txt2"
+                    android:textSize="14px" />
+
                 <RadioGroup
                     android:id="@+id/device_sys_group_sip"
                     android:layout_width="match_parent"
@@ -159,17 +170,6 @@
                     android:orientation="horizontal">
 
                     <RadioButton
-                        android:id="@+id/device_sys_radio_language_on"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/str_yes"
-                        android:textColor="@drawable/radio_button_selector_txt2"
-                        android:button="@null"
-                        android:drawableLeft="@drawable/radio_button_selector_bg2"
-                        android:drawablePadding="@dimen/d5"
-                        android:textSize="14px" />
-
-                    <RadioButton
                         android:id="@+id/device_sys_radio_language_off"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"

+ 23 - 2
android_host/src/main/res/layout/activity_new_nurse_home.xml

@@ -3,6 +3,7 @@
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     >
+
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -264,6 +265,22 @@
                         android:visibility="gone"
                         android:textStyle="bold" />
 
+                    <com.wdkl.ncs.android.lib.widget.BadgeRadioButton
+                        android:id="@+id/nb_device_radio_bt"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:layout_marginLeft="@dimen/d15"
+                        android:layout_weight="1"
+                        android:button="@null"
+                        android:layout_marginRight="@dimen/d15"
+                        android:gravity="center"
+                        android:textColor="@drawable/selector_bottom_btn_text_color"
+                        android:text="@string/str_nb_iot"
+                        android:textStyle="bold"
+                        android:padding="10dp"
+                        android:textSize="20sp" />
+
                     <RadioButton
                         android:id="@+id/menu_more"
                         android:layout_width="match_parent"
@@ -309,7 +326,8 @@
                 android:layout_marginBottom="10dp"
                 android:layout_toLeftOf="@+id/main_rl_3"
                 android:layout_marginLeft="@dimen/d10"
-                android:layout_marginRight="@dimen/d10" />
+                android:layout_marginRight="@dimen/d10"
+                />
 
             <LinearLayout
                 android:id="@+id/main_rl_3"
@@ -368,6 +386,7 @@
                 </LinearLayout>-->
 
             </LinearLayout>
+
         </RelativeLayout>
 
         <!--通话记录界面-->
@@ -380,7 +399,9 @@
         <FrameLayout
             android:id="@+id/call_frame_new"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
+            android:layout_height="match_parent"
+
+            />
 
     </RelativeLayout>
 </layout>

+ 65 - 0
android_host/src/main/res/layout/adapter_message_item.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/ll_message"
+        android:layout_width="match_parent"
+        android:layout_height="100dp"
+        android:layout_marginTop="10dp"
+        android:gravity="center_vertical"
+        android:padding="20dp">
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:layout_marginRight="20dp"
+            android:gravity="center"
+            android:src="@mipmap/ic_note_message" />
+
+        <TextView
+            android:id="@+id/tv_message_content"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:layout_marginRight="20dp"
+            android:layout_weight="4"
+            android:gravity="center_vertical"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:text="----"
+            android:textColor="@color/black"
+            android:textSize="32sp" />
+
+        <ImageView
+            android:id="@+id/iv_message_play"
+            android:layout_width="36dp"
+            android:layout_height="match_parent"
+            android:src="@drawable/ic_message" />
+
+        <TextView
+            android:id="@+id/tv_message_creator"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="10dp"
+            android:layout_marginRight="10dp"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:text="--"
+            android:textColor="@color/black"
+            android:textSize="24sp" />
+
+        <TextView
+            android:id="@+id/tv_message_time"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="10dp"
+            android:layout_marginRight="10dp"
+            android:layout_weight="2"
+            android:gravity="center"
+            android:text="--"
+            android:textSize="20sp" />
+
+    </LinearLayout>
+</layout>

+ 25 - 0
android_host/src/main/res/layout/adapter_nb_iot_device.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="140dp"
+        android:layout_height="120dp"
+        android:padding="10dp"
+        android:background="@drawable/item_selector">
+
+        <ImageView
+            android:layout_width="80dp"
+            android:layout_height="80dp"
+            android:layout_gravity="center_vertical"
+            android:background="@drawable/nb_iot2" />
+
+        <TextView
+            android:id="@+id/tv_nb_iot_device"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="10dp"
+            android:text="--"
+            android:textSize="20sp" />
+
+    </LinearLayout>
+</layout>

+ 49 - 0
android_host/src/main/res/layout/confirm_dialog.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="20dp"
+    android:gravity="center"
+    android:orientation="vertical"
+    android:background="@drawable/loading_bg_ripple_shape">
+
+    <TextView
+        android:id="@+id/confirm_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
+        android:padding="8dp"
+        android:text=""
+        android:textColor="@color/red_color"
+        android:textSize="32sp"
+        android:gravity="center" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="40dp"
+        android:layout_marginBottom="20dp"
+        android:gravity="center">
+        <Button
+            android:id="@+id/confirm_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/shape_main_hos_txt_bg"
+            android:padding="8dp"
+            android:text="@string/str_confirm"
+            android:textSize="20sp"
+            android:textColor="@drawable/selector_bottom_btn_text_color"/>
+
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:background="@drawable/shape_password_bt_bg"
+            android:padding="8dp"
+            android:text="@string/str_cancel"
+            android:textSize="20sp"
+            android:textColor="@drawable/selector_bottom_btn_text_color"/>
+    </LinearLayout>
+
+</LinearLayout>

+ 23 - 0
android_host/src/main/res/layout/creator_item.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:orientation="vertical"
+    android:background="#e7e7e7">
+
+    <TextView
+        android:id="@+id/tv_frame_name"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:padding="8dp"
+        android:gravity="center"
+        android:text="--"
+        android:textSize="26sp"
+        android:textColor="@color/black" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/black" />
+
+</LinearLayout>

+ 143 - 0
android_host/src/main/res/layout/fragment_message.xml

@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:bind="http://schemas.android.com/apk/res-auto">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="8dp"
+        >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="8dp"
+        android:background="@drawable/shape_bed_bg"
+        >
+
+        <ImageView
+            android:id="@+id/message_title_img"
+            android:layout_width="@dimen/d20"
+            android:layout_height="@dimen/d20"
+            android:background="@mipmap/yisheng"
+            android:layout_marginLeft="@dimen/d28"
+            android:layout_marginTop="@dimen/d20" />
+
+        <TextView
+            android:id="@+id/message_title_t"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/d10"
+            android:layout_marginTop="@dimen/d16"
+            android:layout_toRightOf="@+id/message_title_img"
+            android:text="@string/str_message_list"
+            android:textColor="@color/black"
+            android:textSize="@dimen/font_size_20"
+            android:textStyle="bold" />
+
+        <ImageView
+            android:id="@+id/message_host_emptyImageView"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:src="@mipmap/list"
+            android:layout_gravity="center"
+            android:layout_below="@+id/doctor_img"
+            android:visibility="gone"
+            />
+
+        <com.scwang.smartrefresh.layout.SmartRefreshLayout
+            android:id="@+id/message_refresh"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_below="@+id/message_title_img"
+            bind:srlEnableLoadMore="false"
+            android:padding="@dimen/d10"
+            bind:srlEnableRefresh="true">
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_messages"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:padding="10dp"/>
+
+        </com.scwang.smartrefresh.layout.SmartRefreshLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/d80"
+            android:layout_marginTop="@dimen/d23"
+            android:layout_marginLeft="@dimen/d20"
+            android:layout_alignParentBottom="true"
+            android:orientation="horizontal"
+            android:background="@drawable/shape_bed_bg"
+            android:gravity="center">
+            <Button
+                android:id="@+id/btn_first_page"
+                android:layout_width="@dimen/d92"
+                android:layout_height="@dimen/d35"
+                android:gravity="center"
+                android:background="@drawable/shape_button_bg2"
+                android:text="@string/str_page_up"
+                android:layout_marginRight="@dimen/d20"
+                android:textSize="16sp"
+                android:visibility="gone"
+                android:textColor="@color/cc"/>
+
+            <Button
+                android:id="@+id/btn_pre_page"
+                android:layout_width="@dimen/d92"
+                android:layout_height="@dimen/d35"
+                android:gravity="center"
+                android:background="@drawable/shape_button_bg2"
+                android:text="@string/str_page_up"
+                android:textSize="16sp"
+                android:textColor="@color/cc"/>
+            <TextView
+                android:id="@+id/tv_page_no"
+                android:layout_width="@dimen/d39"
+                android:layout_height="@dimen/d39"
+                android:text="1"
+                android:textColor="@color/white"
+                android:background="@drawable/shape_papg_bg"
+                android:textSize="@dimen/font_size_20"
+                android:layout_marginLeft="@dimen/d10"
+                android:gravity="center" />
+            <Button
+                android:id="@+id/btn_next_page"
+                android:layout_width="@dimen/d92"
+                android:layout_height="@dimen/d35"
+                android:gravity="center"
+                android:background="@drawable/shape_button_bg2"
+                android:text="@string/str_page_down"
+                android:textSize="16sp"
+                android:layout_marginLeft="@dimen/d10"
+                android:textColor="@color/cc"/>
+
+            <TextView
+                android:id="@+id/yz_view_all_page"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="@color/cost_list_title"
+                android:textSize="@dimen/font_size_18"
+                android:layout_marginLeft="@dimen/d10"
+                android:visibility="gone"
+                android:gravity="center" />
+            <Button
+                android:id="@+id/btn_add_message"
+                android:layout_width="@dimen/d92"
+                android:layout_height="@dimen/d35"
+                android:layout_alignParentRight="true"
+                android:background="@drawable/shape_main_hos_txt_bg"
+                android:textColor="@drawable/selector_bottom_btn_text_color"
+                android:text="@string/str_add_message"
+                android:layout_marginLeft="@dimen/d20"
+                android:textSize="@dimen/font_size_16" />
+        </LinearLayout>
+    </RelativeLayout>
+
+
+
+    </RelativeLayout>
+
+
+</layout>

+ 127 - 0
android_host/src/main/res/layout/fragment_nb_iot_device.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:bind="http://schemas.android.com/apk/res-auto">
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:padding="10dp"
+            android:background="#EAF2F9"
+            android:orientation="vertical">
+
+            <RadioGroup
+                android:id="@+id/group_host"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <RadioButton
+                    android:id="@+id/rb_offline_device"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingTop="20dp"
+                    android:paddingBottom="20dp"
+                    android:background="@drawable/selector_button_bg_color"
+                    android:button="@null"
+                    android:gravity="center"
+                    android:text="@string/str_offline_device"
+                    android:textSize="24sp"/>
+
+                <RadioButton
+                    android:id="@+id/rb_low_battery_device"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="20dp"
+                    android:paddingTop="20dp"
+                    android:paddingBottom="20dp"
+                    android:background="@drawable/selector_button_bg_color"
+                    android:button="@null"
+                    android:gravity="center"
+                    android:text="@string/str_low_battery_device"
+                    android:textSize="24sp"/>
+            </RadioGroup>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:padding="10dp"
+                android:orientation="vertical">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/str_nb_iot_voice_warning"
+                    android:textColor="#000000"
+                    android:textSize="24sp" />
+
+                <RadioGroup
+                    android:id="@+id/group_voice_warning"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp"
+                    android:orientation="horizontal">
+
+                    <RadioButton
+                        android:id="@+id/rb_voice_warning_on"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/str_yes"
+                        android:textSize="20sp" />
+
+                    <RadioButton
+                        android:id="@+id/rb_voice_warning_off"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:text="@string/str_no"
+                        android:textSize="20sp" />
+                </RadioGroup>
+
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_weight="2.5"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            >
+            <ImageView
+                android:id="@+id/rv_nb_iot_emptyImageView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:src="@mipmap/list"
+                android:layout_gravity="center"
+                android:layout_below="@+id/doctor_img"
+                />
+
+            <com.scwang.smartrefresh.layout.SmartRefreshLayout
+                android:id="@+id/nb_iot_device_refresh"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="2.5"
+                bind:srlEnableLoadMore="false"
+                bind:srlEnableRefresh="true">
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_nb_iot_device"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:background="#EAF2F9"
+                    android:padding="10dp"/>
+
+
+            </com.scwang.smartrefresh.layout.SmartRefreshLayout>
+
+        </LinearLayout>
+
+
+
+
+    </LinearLayout>
+
+</layout>

+ 202 - 0
android_host/src/main/res/layout/message_create_dialog_activity.xml

@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+     >
+
+
+    <LinearLayout
+        android:id="@+id/ll_message_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/white"
+        android:gravity="center_horizontal"
+        android:padding="10dp"
+        android:orientation="vertical"
+        >
+
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:paddingLeft="20dp"
+        android:paddingRight="20dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:text="@string/str_message_type"
+            android:textColor="#000000"
+            android:textSize="24sp" />
+
+        <RadioGroup
+            android:id="@+id/group_message_type"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="20dp"
+            android:orientation="horizontal">
+
+            <RadioButton
+                android:id="@+id/radio_text_msg"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/str_text_message"
+                android:textColor="#000000"
+                android:textSize="24sp"
+                android:button="@null"
+                android:drawableLeft="@drawable/radio_button_selector_bg2"
+                android:drawablePadding="@dimen/d5"
+                android:checked="true"/>
+
+            <RadioButton
+                android:id="@+id/radio_voice_msg"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="20dp"
+                android:text="@string/str_voice_message"
+                android:textColor="#000000"
+                android:button="@null"
+                android:drawableLeft="@drawable/radio_button_selector_bg2"
+                android:drawablePadding="@dimen/d5"
+                android:textSize="24sp" />
+        </RadioGroup>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="60dp"
+        android:layout_marginTop="5dp"
+        android:paddingLeft="20dp"
+        android:paddingRight="20dp">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:text="@string/str_message_creator"
+            android:textColor="#000000"
+            android:textSize="24sp"/>
+        <Spinner
+            android:id="@+id/spinner_creator"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginStart="10dp"
+            android:gravity="center_vertical"
+            android:spinnerMode="dropdown"/>
+
+    </LinearLayout>
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="210dp"
+        android:paddingTop="10dp"
+        >
+
+        <EditText
+            android:id="@+id/edit_text_message"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:textColor="#000000"
+            android:textSize="28sp"
+            android:gravity="left|top"
+            android:padding="@dimen/d10"
+            android:hint="@string/str_message_hint"
+            android:background="@drawable/shape_n_login_ed_bg2"
+            android:visibility="visible"/>
+
+        <LinearLayout
+            android:id="@+id/ll_voice_message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:visibility="gone"
+            >
+
+            <Chronometer
+                android:id="@+id/voice_record_timer"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:textColor="#000000"
+                android:textSize="18sp"
+                android:text="00:00" />
+
+            <Button
+                android:id="@+id/btn_voice_record"
+                android:layout_width="80dp"
+                android:layout_height="80dp"
+                android:layout_marginTop="10dp"
+                android:layout_gravity="center"
+                android:background="@drawable/selector_record_btn" />
+
+            <TextView
+                android:id="@+id/tv_voice_record"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:gravity="center"
+                android:text="@string/str_voice_msg_btn_text"
+                android:textColor="#000000"
+                android:textSize="20sp"/>
+
+            <TextView
+                android:id="@+id/tv_voice_msg_state"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"
+                android:gravity="center"
+                android:text="@string/str_empty_voice_msg"
+                android:textColor="#ff0000"
+                android:textSize="20sp"/>
+        </LinearLayout>
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="20dp">
+        <Button
+            android:id="@+id/btn_add_save"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingLeft="40dp"
+            android:paddingRight="40dp"
+            android:paddingTop="10dp"
+            android:paddingBottom="10dp"
+            android:background="@drawable/shape_main_hos_txt_bg"
+            android:textColor="@drawable/selector_bottom_btn_text_color"
+            android:text="@string/str_save"
+            android:textSize="20sp"
+            style="?android:attr/buttonBarButtonStyle" />
+
+        <View
+            android:layout_width="60dp"
+            android:layout_height="60dp"/>
+
+        <Button
+            android:id="@+id/btn_add_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingLeft="40dp"
+            android:paddingRight="40dp"
+            android:paddingTop="10dp"
+            android:paddingBottom="10dp"
+            android:background="@drawable/shape_main_hos_txt_bg"
+            android:textColor="@drawable/selector_bottom_btn_text_color"
+            android:text="@string/str_cancel"
+            android:textSize="20sp"
+            style="?android:attr/buttonBarButtonStyle" />
+    </LinearLayout>
+
+    </LinearLayout>
+
+
+</LinearLayout>
+</layout>

+ 46 - 0
android_host/src/main/res/layout/message_dialog.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:padding="20dp"
+    android:gravity="center"
+    android:orientation="vertical"
+    android:background="@drawable/loading_bg_ripple_shape">
+
+    <TextView
+        android:id="@+id/message_text"
+        android:layout_width="720dp"
+        android:layout_height="340dp"
+        android:layout_marginTop="20dp"
+        android:padding="8dp"
+        android:gravity="start"
+        android:textColor="@color/black"
+        android:textSize="32sp"
+        android:letterSpacing="0.2"
+        android:lineSpacingExtra="8dp"
+        android:scrollbars="vertical"
+        android:fadeScrollbars="false"/>
+
+    <ImageButton
+        android:id="@+id/btn_message_play"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
+        android:background="@android:color/transparent"
+        android:src="@drawable/ic_bc_play"
+        android:visibility="gone"/>
+
+    <Button
+        android:id="@+id/btn_cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
+        android:layout_marginBottom="20dp"
+        android:gravity="center"
+        android:background="@drawable/shape_password_bt_bg"
+        android:padding="10dp"
+        android:text="@string/str_confirm"
+        android:textSize="28sp"
+        android:textColor="@drawable/selector_bottom_btn_text_color"/>
+
+</LinearLayout>

+ 21 - 0
android_host/src/main/res/values-es/strings.xml

@@ -107,6 +107,24 @@
     <string name="str_manage_host">Administrar host</string>
     <string name="str_trusteeship">Custodia</string>
     <string name="str_led">LED</string>
+    <string name="str_note_message">Mensaje</string>
+    <string name="str_add_message">Agregar mensaje</string>
+    <string name="str_message_type">Tipo de mensaje:</string>
+    <string name="str_text_message">Texto</string>
+    <string name="str_voice_message">Voz</string>
+    <string name="str_message_creator">Creador:</string>
+    <string name="str_nb_iot">Dispositivo IoT</string>
+    <string name="str_offline_device">Dispositivo sin conexión</string>
+    <string name="str_low_battery_device">Dispositivo con batería baja</string>
+    <string name="str_nb_iot_voice_warning">Advertencia de voz de IoT</string>
+    <string name="iot_device_name">Nombre:%s</string>
+    <string name="iot_device_id">ID:%d</string>
+    <string name="iot_device_mac">MAC:%s</string>
+    <string name="iot_device_frame_name">Ubicación:%s</string>
+    <string name="iot_device_warning">¡Advertencia de error del dispositivo NB!</string>
+    <string name="str_nurse_settings">Estación de enfermería - Configuración</string>
+    <string name="str_doctor_settings">Host de doctor - Configuración</string>
+
     <string name="str_visit">Visita con cita</string>
     <string name="str_settings">Configuración</string>
     <string name="str_delete">Eliminar</string>
@@ -295,6 +313,9 @@
     <string name="str_emergency_list">Lista de Emergencias</string>
     <string name="str_blue_code_list">Lista de Códigos Azules</string>
 
+    <string name="str_message_hint">Ingrese su mensaje</string>
+    <string name="str_message_list">Lista de mensajes</string>
+
 
 
 

+ 20 - 0
android_host/src/main/res/values-ru/strings.xml

@@ -108,6 +108,24 @@
     <string name="str_manage_host">Пульт медсестры</string>
     <string name="str_trusteeship">Доверительное управление</string>
     <string name="str_led">светодиод</string>
+    <string name="str_note_message">Сообщение</string>
+    <string name="str_add_message">Добавить сообщение</string>
+    <string name="str_message_type">Тип сообщения:</string>
+    <string name="str_text_message">Текст</string>
+    <string name="str_voice_message">Голосовое</string>
+    <string name="str_message_creator">Создатель:</string>
+    <string name="str_nb_iot">Устройство IoT</string>
+    <string name="str_offline_device">Оффлайн-устройство</string>
+    <string name="str_low_battery_device">Устройство с низким зарядом</string>
+    <string name="str_nb_iot_voice_warning">Голосовое предупреждение IoT</string>
+    <string name="iot_device_name">Имя:%s</string>
+    <string name="iot_device_id">ID:%d</string>
+    <string name="iot_device_mac">MAC:%s</string>
+    <string name="iot_device_frame_name">Местоположение:%s</string>
+    <string name="iot_device_warning">Предупреждение об ошибке устройства NB!</string>
+    <string name="str_nurse_settings">Медицинская станция - Настройки</string>
+    <string name="str_doctor_settings">Хост доктора - Настройки</string>
+
     <string name="str_visit">Назначенный визит</string>
     <string name="str_settings">Настройки</string>
     <string name="str_delete">Удалить</string>
@@ -300,6 +318,8 @@
     <string name="str_emergency_list">Emergency List</string>
     <string name="str_blue_code_list">BlueCode List</string>
 
+    <string name="str_message_hint">Введите ваше сообщение</string>
+    <string name="str_message_list">Список сообщений</string>
 
 
 

+ 36 - 0
android_host/src/main/res/values-zh/strings.xml

@@ -109,6 +109,23 @@
     <string name="str_manage_host">总控主机</string>
     <string name="str_trusteeship">托管</string>
     <string name="str_led">点阵屏</string>
+    <string name="str_note_message">留言</string>
+    <string name="str_add_message">添加留言</string>
+    <string name="str_message_type">留言类型:</string>
+    <string name="str_text_message">文本</string>
+    <string name="str_voice_message">语音</string>
+    <string name="str_message_creator">创建人:</string>
+    <string name="str_nb_iot">IoT设备</string>
+    <string name="str_offline_device">离线设备</string>
+    <string name="str_low_battery_device">低电设备</string>
+    <string name="str_nb_iot_voice_warning">语音提醒</string>
+    <string name="iot_device_name">名称:%s</string>
+    <string name="iot_device_id">ID:%d</string>
+    <string name="iot_device_mac">MAC:%s</string>
+    <string name="iot_device_frame_name">位置:%s</string>
+    <string name="iot_device_warning">NB设备异常提醒!</string>
+    <string name="str_nurse_settings">护士主机 - 设置</string>
+    <string name="str_doctor_settings">医生机 - 设置</string>
     <string name="str_visit">预约探视</string>
     <string name="str_settings">设置</string>
     <string name="str_delete">删除</string>
@@ -116,6 +133,9 @@
     <string name="str_manager_host">总控主机</string>
     <string name="server_config">服务器配置</string>
 
+
+
+
     <string name="broadcast_init_error">广播初始化异常</string>
     <string name="broadcast_init_success">广播初始化完成</string>
     <string name="broadcast_start_warning">请先启动广播</string>
@@ -125,6 +145,19 @@
     <string name="broadcast_playing">正在广播…</string>
     <string name="broadcast_stop">广播停止</string>
 
+    <string name="str_voice_msg_btn_title">松开保存,滑动取消</string>
+    <string name="str_voice_msg_btn_text">按住说话</string>
+    <string name="str_voice_msg_record_loss">说话时间太短</string>
+    <string name="str_voice_msg_record_cancel">语音留言已取消</string>
+    <string name="str_empty_voice_msg">未录制语音</string>
+    <string name="str_delete_tip">确认删除?</string>
+    <string name="str_message_content_error">留言内容为空</string>
+    <string name="str_voice_message_invalid">语音留言文件无效</string>
+    <string name="str_message_save_success">留言成功!</string>
+    <string name="str_record_message_success">语音录制成功!</string>
+    <string name="str_invalid_creator_name">请先选择创建人</string>
+
+
     <string name="setting_day_night_time">白天-晚上时间设置</string>
     <string name="setting_call_type">播报模式:</string>
     <string name="setting_call_type_tts">TTS</string>
@@ -303,4 +336,7 @@
     <string name="str_alarm_list">提醒列表</string>
     <string name="str_emergency_list">紧急列表</string>
     <string name="str_blue_code_list">BlueCode列表</string>
+
+    <string name="str_message_hint">输入您的留言</string>
+    <string name="str_message_list">留言列表</string>
 </resources>

+ 23 - 0
android_host/src/main/res/values/strings.xml

@@ -110,6 +110,23 @@
     <string name="str_manage_host">Manager Host</string>
     <string name="str_trusteeship">Managed</string>
     <string name="str_led">LED</string>
+    <string name="str_note_message">Message</string>
+    <string name="str_add_message">Add message</string>
+    <string name="str_message_type">Message type:</string>
+    <string name="str_text_message">Text</string>
+    <string name="str_voice_message">Voice</string>
+    <string name="str_message_creator">Creator:</string>
+    <string name="str_nb_iot">IoT device</string>
+    <string name="str_offline_device">Offline device</string>
+    <string name="str_low_battery_device">Low battery device</string>
+    <string name="str_nb_iot_voice_warning">Voice warning</string>
+    <string name="iot_device_name">Name:%s</string>
+    <string name="iot_device_id">ID:%d</string>
+    <string name="iot_device_mac">MAC:%s</string>
+    <string name="iot_device_frame_name">Location:%s</string>
+    <string name="iot_device_warning">NB Device error warning!</string>
+    <string name="str_nurse_settings">Nurse station - Settings</string>
+    <string name="str_doctor_settings">Doctor host - Settings</string>
     <string name="str_visit">visit</string>
     <string name="str_settings">Settings</string>
     <string name="str_delete">Delete</string>
@@ -305,6 +322,12 @@
     <string name="str_emergency_list">Emergency List</string>
     <string name="str_blue_code_list">BlueCode List</string>
 
+    <string name="str_message_hint">Enter your message</string>
+    <string name="str_message_list">Message List</string>
+
+
+
+
 
 
 </resources>

+ 1 - 1
common/build.gradle

@@ -63,7 +63,7 @@ dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
     implementation 'androidx.core:core-ktx:1.3.1'
 //    implementation 'androidx.appcompat:appcompat:1.2.0'
-    implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
+
     implementation 'com.google.android.material:material:1.2.1'
     //testImplementation 'junit:junit:4.+'
     androidTestImplementation 'androidx.test.ext:junit:1.1.2'

+ 5 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeHandle.kt

@@ -152,4 +152,9 @@ object TimeHandle {
         val format = SimpleDateFormat(dataFormat)
         return format.format(date)
     }
+    fun getRecTimeFilename(): String {
+        val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss")
+        val date = Date()
+        return dateFormat.format(date)
+    }
 }

+ 20 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/WidgetsUtil.java

@@ -3,6 +3,7 @@ package com.wdkl.ncs.android.lib.utils;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
@@ -18,6 +19,25 @@ public class WidgetsUtil {
         showToastWithImage(message, dp, dp);
     }
 
+    //带图片的toast
+    public static void showToastWithImage(String message, float widthDp, float heightDp, int resId) {
+        View toastView = LayoutInflater.from(BaseApplication.appContext).inflate(R.layout.view_toast_image2, null);
+        LinearLayout layout = (LinearLayout) toastView.findViewById(R.id.toast_linear);
+        //动态设置toast控件的宽高度
+        //这里用了一个将dp转换为px的工具类PxUtil
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams((int) DisplayUtils.dp2px(BaseApplication.appContext, widthDp), (int)DisplayUtils.dp2px(BaseApplication.appContext, heightDp));
+        layout.setLayoutParams(layoutParams);
+        TextView textView = toastView.findViewById(R.id.tv_toast_clear);
+        ImageView imageView = toastView.findViewById(R.id.ic_toast);
+        textView.setText(message);
+        imageView.setImageResource(resId);
+        Toast mToast = new Toast(BaseApplication.appContext);
+        mToast.setDuration(Toast.LENGTH_LONG);
+        mToast.setGravity(Gravity.CENTER, 0, 0);
+        mToast.setView(toastView);
+        mToast.show();
+    }
+
     public static void showToastWithImage(String message, float widthDp, float heightDp) {
         View toastView = LayoutInflater.from(BaseApplication.appContext).inflate(R.layout.view_toast_image, null);
         LinearLayout layout = (LinearLayout) toastView.findViewById(R.id.toast_linear);

+ 85 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/BadgeRadioButton.java

@@ -0,0 +1,85 @@
+package com.wdkl.ncs.android.lib.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+import java.util.List;
+
+import androidx.appcompat.widget.AppCompatRadioButton;
+
+public class BadgeRadioButton extends AppCompatRadioButton implements BadgeUtil.Badge {
+
+    private int number = -1;
+    private BadgeUtil.BadgeDrawer drawer;
+    private String id;
+
+    public BadgeRadioButton(Context context) {
+        super(context);
+    }
+
+    public BadgeRadioButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public BadgeRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        Drawable[] drawables = getCompoundDrawables();
+        Drawable drawable = drawables[0];
+        if (drawable != null) {
+            int gravity = getGravity();
+            int left = 0;
+            if (gravity == Gravity.CENTER) {
+                left = ((int) (getWidth() - drawable.getIntrinsicWidth() - getPaint().measureText(getText().toString())) / 2);
+            }
+            drawable.setBounds(left, 0, left + drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+
+            if (drawer == null){
+                drawer = drawer();
+            }
+            drawer.draw(canvas);
+        }else {
+            // drawable 是 null,不做任何操作
+        }
+
+    }
+
+    @Override
+    public void update(int number) {
+        this.number = number;
+        invalidate();
+    }
+
+    @Override
+    public int getNumber() {
+        return number;
+    }
+
+    @Override
+    public BadgeUtil.BadgeDrawer drawer() {
+        if (drawer == null) drawer = new BadgeUtil.BadgeDrawer(this);
+        return drawer;
+    }
+
+    @Override
+    public String getBadgeId() {
+        return id;
+    }
+
+    @Override
+    public void setBadgeId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public void updateBadge(List<BadgeUtil.BadgeNumber> badgeNumbers) {
+
+    }
+}

+ 318 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/BadgeUtil.java

@@ -0,0 +1,318 @@
+package com.wdkl.ncs.android.lib.widget;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class BadgeUtil {
+
+    /**
+     * The Badge
+     */
+    public interface Badge extends UpdateAble {
+
+        int getNumber();
+
+        BadgeDrawer drawer();
+
+        String getBadgeId();
+
+        void setBadgeId(String id);
+    }
+
+    public interface UpdateAble {
+        void update(int number);
+        void updateBadge(List<BadgeNumber> badgeNumbers);
+    }
+
+    /**
+     * This do the draw job.
+     * for View you should call {@link #draw(Canvas)} in onDraw(Canvas) method.
+     * for ViewGroup you should call {@link #draw(Canvas)} in dispatchDraw(Canvas) method.
+     */
+    public static class BadgeDrawer {
+        private Badge badge;
+        private Paint paint;
+        private int textSize = dpToPx(8);
+        private int radius = dpToPx(6);
+        private int paddingTop = dpToPx(6);
+        private int paddingRight = dpToPx(4);
+        private int minWidth = dpToPx(48);
+        private int minHeight = dpToPx(48);
+        private int textColor = Color.WHITE;
+        private int backgroundColor = Color.RED;
+
+        public BadgeDrawer(Badge badge) {
+            this.badge = badge;
+
+            if (((View) badge).getMinimumWidth() < minWidth) {
+                ((View) badge).setMinimumWidth(minWidth);
+            }
+
+            if (((View) badge).getMeasuredHeight() < minHeight) {
+                ((View) badge).setMinimumHeight(minHeight);
+            }
+
+            paint = new Paint();
+            paint.setAntiAlias(true);
+        }
+
+        public void draw(Canvas canvas) {
+            View target = (View) badge;
+            if (target.getWidth() == 0 || target.getHeight() == 0) {
+                return;
+                //don't draw if view is not ready.
+            }
+
+            //小于0不画红点
+            if (badge.getNumber() < 0) {
+                return;
+            }
+
+            beforeDrawBackGround();
+
+            int centerX = target.getWidth() - paddingRight - radius;
+            int centerY = paddingTop + radius;
+
+            canvas.drawCircle(centerX, centerY, radius, paint);
+
+            //等于0只画红点,不画数字
+            if (badge.getNumber() == 0) {
+                return;
+            }
+
+            beforeDrawText();
+
+            Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
+            canvas.drawText(
+                    badge.getNumber() <= 9 ? String.valueOf(badge.getNumber()) : "9+"
+                    , centerX, centerY - (fontMetrics.bottom + fontMetrics.top) / 2
+                    , paint
+            );
+        }
+
+        private void beforeDrawBackGround() {
+            paint.setColor(backgroundColor);
+            paint.setStyle(Paint.Style.FILL);
+        }
+
+        private void beforeDrawText() {
+            paint.setColor(textColor);
+            paint.setStyle(Paint.Style.STROKE);
+            paint.setTextAlign(Paint.Align.CENTER);
+            paint.setStrokeWidth(dpToPx(1));
+            paint.setTextSize(textSize);
+        }
+
+        public BadgeDrawer setTextSize(int textSize, boolean inDp) {
+            if (inDp) {
+                textSize = dpToPx(textSize);
+            }
+            this.textSize = textSize;
+            return this;
+        }
+
+        public BadgeDrawer setRadius(int radius, boolean inDp) {
+            if (inDp) {
+                radius = dpToPx(radius);
+            }
+            this.radius = radius;
+            return this;
+        }
+
+        public BadgeDrawer setPaddingTop(int paddingTop, boolean inDp) {
+            if (inDp) {
+                paddingTop = dpToPx(paddingTop);
+            }
+            this.paddingTop = paddingTop;
+            return this;
+        }
+
+        public BadgeDrawer setPaddingRight(int paddingRight, boolean inDp) {
+            if (inDp) {
+                paddingRight = dpToPx(paddingRight);
+            }
+            this.paddingRight = paddingRight;
+            return this;
+        }
+
+        public BadgeDrawer setTextColor(int textColor) {
+            this.textColor = textColor;
+            return this;
+        }
+
+        public BadgeDrawer setBackgroundColor(int backgroundColor) {
+            this.backgroundColor = backgroundColor;
+            return this;
+        }
+    }
+
+    /**
+     *You may need this manager class if you are gonna refresh numbers by http request.
+     */
+    public static class BadgeManager extends Timer {
+
+        private long delay = 100;
+        private long period = 10000L;
+        private Notifier notifier;
+        private TimerTask task;
+        private boolean enabled = false;
+
+        public static BadgeManager create() {
+            return new BadgeManager();
+        }
+
+        public BadgeManager delay(long delay) {
+            this.delay = delay;
+            return this;
+        }
+
+        public BadgeManager period(long period) {
+            this.period = period;
+            return this;
+        }
+
+        //You need a notifier to set numbers to registered badges.
+        public BadgeManager notifier(Notifier notifier) {
+            this.notifier = notifier;
+            return this;
+        }
+
+        public BadgeManager start() {
+            if (task == null) {
+                task = new TimerTask() {
+                    @Override
+                    public void run() {
+                        //Make your http request here.
+                    }
+                };
+            }
+            schedule(task, delay, period);
+            enabled = true;
+            return this;
+        }
+
+        /**
+         * this method should be called on UI Thread.
+         */
+        public void onBadgeNumbersGet(List<BadgeNumber> badgeNumbers){
+            if (notifier != null){
+                notifier.notifyUpdate(badgeNumbers);
+            }
+        }
+
+        public BadgeManager stop() {
+            if (task != null){
+                task.cancel();
+                task = null;
+            }
+            enabled = false;
+            return this;
+        }
+
+        public Notifier getNotifier() {
+            return notifier;
+        }
+    }
+
+    /**
+     * This will tell all the badges that is registered it is time to update.
+     * First you need to register your badges to a Notifier.
+     */
+    public static class Notifier {
+        List<UpdateAble> notifyList = new ArrayList<>();
+        private boolean enable = true;
+        private List<BadgeNumber> cachedNumbers;
+
+        public void notifyUpdate(List<BadgeNumber> badgeNumbers) {
+            cachedNumbers = badgeNumbers;
+            if (!enable) return;
+            for (UpdateAble updateAble : notifyList) {
+                if (updateAble instanceof Badge) {
+                    BadgeNumber number = findNumberById(badgeNumbers, ((Badge) updateAble).getBadgeId());
+                    if (number != null) {
+                        updateAble.update(number.getNumber());
+                    }
+                } else {
+                    updateAble.updateBadge(badgeNumbers);
+                }
+            }
+        }
+
+        public void register(UpdateAble updateAble) {
+            if (updateAble != null && !notifyList.contains(updateAble)) {
+                notifyList.add(updateAble);
+                if (!(updateAble instanceof Badge)) {
+                    updateAble.updateBadge(cachedNumbers);
+                }
+            }
+        }
+
+        public void unRegister(UpdateAble updateAble) {
+            if (updateAble != null && notifyList.contains(updateAble)) {
+                notifyList.remove(updateAble);
+            }
+        }
+
+        public BadgeNumber findNumberById(List<BadgeNumber> badgeNumbers, String id) {
+            for (BadgeNumber number : badgeNumbers) {
+                if (id.equals(number.getId())) {
+                    return number;
+                }
+            }
+            return null;
+        }
+
+        public void disable() {
+            this.enable = false;
+        }
+    }
+
+    public static class BadgeNumber {
+        //Number tobe set to the badge.
+        private int number;
+        //Id of your certain badge.
+        private String id;
+
+        public BadgeNumber() {
+        }
+
+        public BadgeNumber(int number, String id) {
+            this.number = number;
+            this.id = id;
+        }
+
+        public int getNumber() {
+            return number;
+        }
+
+        public void setNumber(int number) {
+            this.number = number;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+    }
+
+    public static float pxToDp(float px) {
+        float densityDpi = Resources.getSystem().getDisplayMetrics().densityDpi;
+        return px / (densityDpi / 160f);
+    }
+
+    public static int dpToPx(float dp) {
+        float density = Resources.getSystem().getDisplayMetrics().density;
+        return Math.round(dp * density);
+    }
+}

BIN
common/src/main/res/drawable/toast_warn.png


+ 32 - 0
common/src/main/res/layout/view_toast_image2.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/toast_relative"
+    android:background="#9A2B2929"
+    android:layout_width="360dp"
+    android:layout_height="320dp">
+
+    <LinearLayout
+        android:id="@+id/toast_linear"
+        android:padding="10dp"
+        android:orientation="vertical"
+        android:layout_width="360dp"
+        android:layout_height="320dp"
+        android:gravity="center">
+
+        <ImageView
+            android:id="@+id/ic_toast"
+            android:layout_width="200dp"
+            android:layout_height="200dp" />
+
+        <TextView
+            android:id="@+id/tv_toast_clear"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:gravity="center"
+            android:textSize="32sp"
+            android:textColor="#FFA5A5"
+            android:text="" />
+    </LinearLayout>
+</RelativeLayout>
+

+ 37 - 4
middleware/src/main/code/com/wdkl/ncs/android/middleware/api/DeviceApi.kt

@@ -1,11 +1,9 @@
 package com.wdkl.ncs.android.middleware.api
 
 import io.reactivex.Observable
+import okhttp3.MultipartBody
 import okhttp3.ResponseBody
-import retrofit2.http.GET
-import retrofit2.http.POST
-import retrofit2.http.Path
-import retrofit2.http.Query
+import retrofit2.http.*
 
 interface DeviceApi {
     @GET("/deviceNurse/getDeviceByEthMac/{ethMac}")
@@ -29,4 +27,39 @@ interface DeviceApi {
     //退出托管
     @POST("/deviceNurse/delete_transfer_id")
     fun cancelTransfer(@Query("device_id") deviceId:Int): Observable<ResponseBody>
+
+    //查询掉线NB Iot设备
+    @GET("/nbdevcie/getoffline/{partId}")
+    fun getNBOfflineDevice(@Path("partId") partId: Int): Observable<ResponseBody>
+
+    //查询低电NB Iot设备
+    @GET("/nbdevcie/getlowbattery/{partId}")
+    fun getNBLowBatteryDevice(@Path("partId") partId: Int): Observable<ResponseBody>
+
+
+    @GET("/deviceNurse/getRemarkByPartId/{partId}")
+    fun getMessages(@Path("partId") partId: Int): Observable<ResponseBody>
+    //分页查询便签留言
+    @POST("/deviceNurse/remark/page")
+    fun getMessageByPage(@Query("page_no") pageNo: Int, @Query("page_size") pageSize: Int, @Query("part_id") partId: Int): Observable<ResponseBody>
+
+    //添加便签留言
+    @POST("/deviceNurse/remark")
+    fun addRemark(@Query("id") id: Int?, @Query("unionId") unionId: String?
+                  ,@Query("createTime") createTime: Long?, @Query("partId") partId: Int
+                  ,@Query("type") type: Int, @Query("memberId") memberId: Int?
+                  ,@Query("createName") createName: String?, @Query("content") content: String?
+                  ,@Query("fileName") fileName: String?, @Query("filePath") filePath: String?): Observable<ResponseBody>
+
+    //删除便签留言
+    @DELETE("/deviceNurse/remark/{ids}")
+    fun deleteRemark(@Path("ids") ids: Int): Observable<ResponseBody>
+
+    //上传文件
+    @Multipart
+    @POST("/ncs/upload/file")
+    fun uploadFile(@Part() file : MultipartBody.Part): Observable<ResponseBody>
+
+    @GET("/deviceNurse/clerks_by_shop_id/{shop_id}")
+    fun getClerks(@Path("shop_id") shopId: Int): Observable<ResponseBody>
 }

+ 5 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/di/PresenterComponent.kt

@@ -139,6 +139,11 @@ interface PresenterComponent {
 
     fun inject(presenter: BroadcastSetPresenter)
 
+    fun inject(presenter: MessagePresenter)
+
+    fun inject(presenter: IotDevicePresenter)
+
+
 
 //    手机端相关的
     fun inject(presenter: HomeFragmentPresenter)

+ 132 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/helper/RecordHelper.java

@@ -0,0 +1,132 @@
+package com.wdkl.ncs.android.middleware.helper;
+
+import android.media.MediaRecorder;
+import android.os.Environment;
+import android.util.Log;
+
+import com.wdkl.ncs.android.lib.utils.TimeHandle;
+
+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 + "/" + TimeHandle.INSTANCE.getRecTimeFilename() + "_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) {
+            try {
+                File file = new File(path);
+                if (file.exists()) {
+                    file.delete();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void deleteAudioFile() {
+        deleteAudioFile(audiofilePath);
+    }
+
+    public String getAudiofilePath() {
+        return audiofilePath;
+    }
+}

+ 30 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/nursehome/IotDeviceContract.kt

@@ -0,0 +1,30 @@
+package com.wdkl.ncs.android.middleware.logic.contract.nursehome
+
+import com.wdkl.ncs.android.lib.base.BaseContract
+import com.wdkl.ncs.android.middleware.model.vo.DeviceVO
+
+/**
+ * 获取其他主机接口
+ */
+interface IotDeviceContract {
+
+
+    /**
+     * 显示数据
+     */
+    interface View:BaseContract.BaseView{
+        fun showOfflineDevice(devices: ArrayList<DeviceVO>)
+
+        fun showLowBatteryDevice(devices: ArrayList<DeviceVO>)
+    }
+
+    /**
+     * 获取数据
+     */
+    interface Presenter:BaseContract.BasePresenter{
+        fun loadOfflineDevice(partId: Int)
+
+        fun loadLowBatteryDevice(partId: Int)
+    }
+
+}

+ 42 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/nursehome/MessageContract.kt

@@ -0,0 +1,42 @@
+package com.wdkl.ncs.android.middleware.logic.contract.nursehome
+
+import com.wdkl.ncs.android.lib.base.BaseContract
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO
+import com.wdkl.ncs.android.middleware.model.vo.RemarksVO
+import okhttp3.MultipartBody
+
+
+interface MessageContract {
+
+    interface View:BaseContract.BaseView{
+        fun showMessages(data: ArrayList<RemarkDO>)
+
+        fun showPageMessages(data: RemarksVO)
+
+        fun resultAddMessage(remarkDO: RemarkDO)
+
+        fun resultDelMessage(data: String)
+
+        fun uploadResponse(result: String)
+
+        fun showClerks(data: ArrayList<ClerkDO>)
+
+    }
+
+    interface Presenter:BaseContract.BasePresenter{
+        fun loadMessage(partId: Int)
+
+        fun loadMessageByPage(pageNo: Int, pageSize: Int, partId: Int)
+
+        fun addNewMessage(remarkDO: RemarkDO)
+
+        fun deleteMessage(ids: Int)
+
+        fun uploadVoiceMsg(multipart : MultipartBody.Part)
+
+        fun loadClerks(shopIp: Int)
+
+    }
+
+}

+ 111 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/nursehome/IotDevicePresenter.kt

@@ -0,0 +1,111 @@
+package com.wdkl.ncs.android.middleware.logic.presenter.nursehome
+
+import com.enation.javashop.net.engine.plugin.connection.ConnectionQuality
+import com.enation.javashop.net.engine.plugin.exception.ExceptionHandle
+import com.enation.javashop.net.engine.utils.ThreadFromUtils
+import com.google.gson.FieldNamingPolicy
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+import com.wdkl.ncs.android.lib.base.RxPresenter
+import com.wdkl.ncs.android.lib.utils.ConnectionObserver
+import com.wdkl.ncs.android.lib.utils.getJsonString
+import com.wdkl.ncs.android.middleware.api.DeviceApi
+import com.wdkl.ncs.android.middleware.di.MiddlewareDaggerComponent
+import com.wdkl.ncs.android.middleware.logic.contract.nursehome.IotDeviceContract
+import com.wdkl.ncs.android.middleware.model.vo.DeviceVO
+import io.reactivex.disposables.Disposable
+import javax.inject.Inject
+
+/**
+ *OtherHostFragment逻辑控制模块
+ */
+class IotDevicePresenter@Inject constructor():RxPresenter<IotDeviceContract.View>(),IotDeviceContract.Presenter {
+
+    @Inject
+    protected lateinit var deviceApi: DeviceApi
+
+    /**
+     *依赖注入初始化
+     */
+    override fun bindDagger() {
+        MiddlewareDaggerComponent.component.inject(this)
+    }
+    /**
+     * 数据监听者
+     */
+    private val observable = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete()
+            providerView().showOfflineDevice(result as ArrayList<DeviceVO>)
+        }
+
+        override fun onErrorWithConnection(
+            error: ExceptionHandle.ResponeThrowable,
+            connectionQuality: ConnectionQuality
+        ) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+
+    }
+
+    private val observable2 = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete()
+            providerView().showLowBatteryDevice(result as ArrayList<DeviceVO>)
+        }
+
+        override fun onErrorWithConnection(
+            error: ExceptionHandle.ResponeThrowable,
+            connectionQuality: ConnectionQuality
+        ) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }
+
+
+    override fun loadOfflineDevice(partId: Int) {
+        deviceApi.getNBOfflineDevice(partId)
+            .map {
+                val data = it.getJsonString()
+                val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                val itemType = object : TypeToken<ArrayList<DeviceVO>>(){}.type
+                val deviceDO = gson.fromJson<ArrayList<DeviceVO>>(data, itemType)
+
+                return@map deviceDO
+            }
+            .compose(ThreadFromUtils.defaultSchedulers())
+            .subscribe(observable)
+    }
+
+    override fun loadLowBatteryDevice(partId: Int) {
+        deviceApi.getNBLowBatteryDevice(partId)
+            .map {
+                val data = it.getJsonString()
+                val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                val itemType = object : TypeToken<ArrayList<DeviceVO>>(){}.type
+                val deviceDO = gson.fromJson<ArrayList<DeviceVO>>(data, itemType)
+
+                return@map deviceDO
+            }
+            .compose(ThreadFromUtils.defaultSchedulers())
+            .subscribe(observable2)
+    }
+
+
+}

+ 219 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/nursehome/MessagePresenter.kt

@@ -0,0 +1,219 @@
+package com.wdkl.ncs.android.middleware.logic.presenter.nursehome
+
+import com.enation.javashop.net.engine.plugin.connection.ConnectionQuality
+import com.enation.javashop.net.engine.plugin.exception.ExceptionHandle
+import com.enation.javashop.net.engine.utils.ThreadFromUtils
+import com.google.gson.FieldNamingPolicy
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+import com.wdkl.ncs.android.lib.base.RxPresenter
+import com.wdkl.ncs.android.lib.utils.*
+import com.wdkl.ncs.android.middleware.api.DeviceApi
+import com.wdkl.ncs.android.middleware.di.MiddlewareDaggerComponent
+import com.wdkl.ncs.android.middleware.logic.contract.nursehome.MessageContract
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO
+import com.wdkl.ncs.android.middleware.model.vo.RemarksVO
+import io.reactivex.disposables.Disposable
+import okhttp3.MultipartBody
+import okhttp3.ResponseBody
+import javax.inject.Inject
+
+class MessagePresenter@Inject constructor():RxPresenter<MessageContract.View>(), MessageContract.Presenter {
+
+    @Inject
+    protected lateinit var deviceApi: DeviceApi
+
+    override fun bindDagger() {
+        MiddlewareDaggerComponent.component.inject(this)
+    }
+
+    private val observable = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete()
+            providerView().showMessages(result as ArrayList<RemarkDO>)
+        }
+
+        override fun onErrorWithConnection(
+                error: ExceptionHandle.ResponeThrowable,
+                connectionQuality: ConnectionQuality
+        ) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }
+
+    /*private val observable2 = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete()
+            providerView().showPageMessages(result as ArrayList<RemarkDO>)
+        }
+
+        override fun onErrorWithConnection(
+            error: ExceptionHandle.ResponeThrowable,
+            connectionQuality: ConnectionQuality
+        ) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }*/
+
+    private val observable3 = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete()
+            providerView().showClerks(result as ArrayList<ClerkDO>)
+        }
+
+        override fun onErrorWithConnection(
+                error: ExceptionHandle.ResponeThrowable,
+                connectionQuality: ConnectionQuality
+        ) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }
+
+    private val observer = object : ConnectionObserver<Any>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: Any, connectionQuality: ConnectionQuality) {
+            providerView().complete("")
+            when (result) {
+                is RemarkDO -> {
+                    providerView().resultAddMessage(result)
+                }
+
+                is String -> {
+                    providerView().resultDelMessage(result)
+                }
+
+                is RemarksVO -> {
+                    providerView().showPageMessages(result)
+                }
+            }
+        }
+
+        override fun onErrorWithConnection(error: ExceptionHandle.ResponeThrowable, connectionQuality: ConnectionQuality) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }
+
+    private val observer2 = object : ConnectionObserver<ResponseBody>() {
+        override fun onStartWithConnection() {
+            providerView()
+        }
+
+        override fun onNextWithConnection(result: ResponseBody, connectionQuality: ConnectionQuality) {
+            providerView().complete("")
+            providerView().uploadResponse(result.getJsonString())
+        }
+
+        override fun onErrorWithConnection(error: ExceptionHandle.ResponeThrowable, connectionQuality: ConnectionQuality) {
+            providerView().onError(error.customMessage)
+        }
+
+        override fun attachSubscribe(var1: Disposable) {
+            addDisposable(var1)
+        }
+    }
+
+
+    override fun loadMessage(partId: Int) {
+        deviceApi.getMessages(partId)
+                .map {
+                    val data = it.getJsonString()
+                    val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                    val itemType = object : TypeToken<ArrayList<RemarkDO>>(){}.type
+                    val remarkList = gson.fromJson<ArrayList<RemarkDO>>(data, itemType)
+
+                    return@map remarkList
+                }
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observable)
+    }
+
+    override fun loadMessageByPage(pageNo: Int, pageSize: Int, partId: Int) {
+        deviceApi.getMessageByPage(pageNo, pageSize, partId)
+                .map {
+                    /*val remarkList = ArrayList<RemarkDO>()
+                    val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                    it.toJsonObject().valueJsonArray("data").arrayObjects().forEach { dic ->
+                        remarkList.add(gson.fromJson(dic.toString(), RemarkDO::class.java))
+                    }*/
+
+                    val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                    return@map gson.fromJson(it.getJsonString(), RemarksVO::class.java)
+                }
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observer)
+    }
+
+    override fun addNewMessage(remarkDO: RemarkDO) {
+        deviceApi.addRemark(remarkDO.id, remarkDO.unionId, remarkDO.createTime, remarkDO.partId, remarkDO.type,
+                remarkDO.memberId, remarkDO.createName, remarkDO.content, remarkDO.fileName, remarkDO.filePath)
+                .map {
+                    val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                    val result = gson.fromJson(it.getJsonString(), RemarkDO::class.java)
+                    return@map result
+                }
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observer)
+    }
+
+    override fun deleteMessage(ids: Int) {
+        deviceApi.deleteRemark(ids)
+                .map {
+                    val result = "Delete success"
+                    return@map result
+                }
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observer)
+    }
+
+    override fun uploadVoiceMsg(multipart: MultipartBody.Part) {
+        deviceApi.uploadFile(multipart)
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observer2)
+    }
+
+    override fun loadClerks(shopIp: Int) {
+        deviceApi.getClerks(shopIp)
+                .map {
+                    val data = it.getJsonString()
+                    val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                    val itemType = object : TypeToken<ArrayList<ClerkDO>>(){}.type
+                    val clerkList = gson.fromJson<ArrayList<ClerkDO>>(data, itemType)
+
+                    return@map clerkList
+                }
+                .compose(ThreadFromUtils.defaultSchedulers())
+                .subscribe(observable3)
+    }
+}

+ 3 - 3
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/RemarkDO.java

@@ -46,7 +46,7 @@ public class RemarkDO implements Serializable {
      */
     @Column(name = "type")
     @ApiModelProperty(value = "备注类型。1,用户备注;2,便签", required = false)
-    private Boolean type;
+    private Integer type;
     /**
      * 用户id。用户备注时不能为空
      */
@@ -116,11 +116,11 @@ public class RemarkDO implements Serializable {
     }
 
 
-    public Boolean getType() {
+    public Integer getType() {
         return type;
     }
 
-    public void setType(Boolean type) {
+    public void setType(Integer type) {
         this.type = type;
     }
 

+ 45 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/RemarksVO.java

@@ -0,0 +1,45 @@
+package com.wdkl.ncs.android.middleware.model.vo;
+
+import com.wdkl.ncs.android.middleware.model.dos.RemarkDO;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class RemarksVO implements Serializable {
+    private Integer pageNo;
+    private Integer pageSize;
+    private Integer dataTotal;
+    private ArrayList<RemarkDO> data;
+
+    public Integer getPageNo() {
+        return pageNo;
+    }
+
+    public void setPageNo(Integer pageNo) {
+        this.pageNo = pageNo;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getDataTotal() {
+        return dataTotal;
+    }
+
+    public void setDataTotal(Integer dataTotal) {
+        this.dataTotal = dataTotal;
+    }
+
+    public ArrayList<RemarkDO> getData() {
+        return data;
+    }
+
+    public void setData(ArrayList<RemarkDO> data) {
+        this.data = data;
+    }
+}

+ 2 - 1
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/BroadcastUtil.java

@@ -35,7 +35,7 @@ public class BroadcastUtil {
     }
 
     //喊话广播
-    public static TcpModel startVoiceBroadcast(Integer fromId, String toIds){
+    public static TcpModel startVoiceBroadcast(Integer fromId, String toGroupIds,String toIds){
         TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.BROADCAST);
         tcpModel.setAction(TcpAction.BroadcastAction.START);
@@ -43,6 +43,7 @@ public class BroadcastUtil {
         Map map = new HashMap<String, String>();
         map.put("type", "voice");
         map.put("toIds", toIds);
+        map.put("toGroupIds", toGroupIds);
         tcpModel.setData(map);
         return tcpModel;
     }

+ 41 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/MessageEvent.kt

@@ -0,0 +1,41 @@
+package com.wdkl.ncs.android.middleware.utils
+
+class MessageEvent {
+
+    private var message: Any? = null
+    private var types: Int? =0
+
+    constructor(type: Int) {
+        types = type
+    }
+
+    companion object {
+        fun build(type: Int, msg: Any): MessageEvent{
+            var msgEvent = MessageEvent(type)
+            msgEvent.message = msg
+            return msgEvent
+        }
+    }
+
+    constructor(tcpModel: Any, type: Int) {
+        message = tcpModel
+        types = type
+    }
+
+    fun getMessage(): Any? {
+        return message
+    }
+
+    fun setMessage(msg: Any?) {
+        this.message = msg
+    }
+
+    fun getType(): Int? {
+        return types
+    }
+
+    fun setType(type: Int?) {
+        this.types = type
+    }
+
+}

+ 43 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/ScreenUtils.java

@@ -0,0 +1,43 @@
+package com.wdkl.ncs.android.middleware.utils;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+public class ScreenUtils {
+    public static int getScreenHeight(Context context) {
+        DisplayMetrics metric = new DisplayMetrics();
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getMetrics(metric);
+        return metric.heightPixels;
+    }
+
+    public static int getScreenWidth(Context context) {
+        DisplayMetrics metric = new DisplayMetrics();
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getMetrics(metric);
+        return metric.widthPixels;
+    }
+
+    /**
+     * px转dp
+     * @param context
+     * @param pxValue
+     * @return
+     */
+    public static int px2dp(Context context, float pxValue){
+        float density = context.getResources().getDisplayMetrics().density;//得到设备的密度
+        return (int) (pxValue/density+0.5f);
+    }
+
+    /**
+     * dp转px
+     * @param context
+     * @param dpValue
+     * @return
+     */
+    public static int dp2px(Context context, float dpValue){
+        float density = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue*density+0.5f);
+    }
+}

+ 52 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/StringUtil.java

@@ -1,5 +1,7 @@
 package com.wdkl.ncs.android.middleware.utils;
 
+import android.text.TextUtils;
+
 import com.wdkl.ncs.android.lib.base.BaseApplication;
 
 public class StringUtil {
@@ -7,8 +9,58 @@ public class StringUtil {
     public static String getResString(int resId) {
         return BaseApplication.appContext.getString(resId);
     }
+    public static String getResString(int resId, Object value) {
+        return BaseApplication.appContext.getString(resId, value);
+    }
 
     public static boolean notEmpty(String str) {
         return str != null && str.length() > 0 && !str.equalsIgnoreCase("null");
     }
+
+    public static String transNumber(String str) {
+        if (TextUtils.isEmpty(str)) {
+            return "";
+        } else {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < str.length(); i++) {
+                char temp = str.charAt(i);
+                switch (temp) {
+                    case '0':
+                        sb.append('零');
+                        break;
+                    case '1':
+                        sb.append('一');
+                        break;
+                    case '2':
+                        sb.append('二');
+                        break;
+                    case '3':
+                        sb.append('三');
+                        break;
+                    case '4':
+                        sb.append('四');
+                        break;
+                    case '5':
+                        sb.append('五');
+                        break;
+                    case '6':
+                        sb.append('六');
+                        break;
+                    case '7':
+                        sb.append('七');
+                        break;
+                    case '8':
+                        sb.append('八');
+                        break;
+                    case '9':
+                        sb.append('九');
+                        break;
+                    default:
+                        sb.append(temp);
+                }
+            }
+
+            return sb.toString();
+        }
+    }
 }

+ 2 - 1
resource/build.gradle

@@ -22,16 +22,17 @@ android {
         }
     }
    dependencies{
-
        /**
         * 单元测试
         */
        testCompile 'junit:junit:4.12'
+       implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
    }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
+
     }
 }
 

+ 6 - 0
resource/src/main/res/drawable/ic_bc_play.xml

@@ -0,0 +1,6 @@
+<vector android:height="64dp" android:tint="#E84C02"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="64dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5 -6,4.5z"/>
+</vector>

+ 5 - 0
resource/src/main/res/drawable/ic_message.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+</vector>

android_bed/src/main/res/drawable/shape_button_bg2.xml → resource/src/main/res/drawable/shape_button_bg2.xml


android_bed/src/main/res/drawable/shape_papg_bg.xml → resource/src/main/res/drawable/shape_papg_bg.xml


BIN
resource/src/main/res/mipmap-mdpi/ic_note_message.png


BIN
resource/src/main/res/mipmap-mdpi/ic_record_normal.png


BIN
resource/src/main/res/mipmap-mdpi/ic_record_press.png


+ 12 - 0
resource/src/main/res/values-es/strings.xml

@@ -112,6 +112,15 @@
     <string name="str_voice_msg_btn_text">Presione para grabar el mensaje</string>
     <string name="str_voice_msg_record_loss">el tiempo es demasiado corto</string>
     <string name="str_voice_msg_record_cancel">Mensaje de voz cancelado</string>
+    <string name="str_empty_voice_msg">No hay mensaje de voz</string>
+    <string name="str_delete_tip">¿Eliminar?</string>
+    <string name="str_message_content_error">Mensaje inválido</string>
+    <string name="str_voice_message_invalid">Mensaje de voz inválido</string>
+    <string name="str_message_save_success">¡Éxito!</string>
+    <string name="str_record_message_success">¡Grabación exitosa!</string>
+    <string name="str_invalid_creator_name">Por favor, seleccione un creador</string>
+
+
     <string name="str_voice_msg_send_success">envío exitoso</string>
     <string name="str_voice_msg_send_fail">envío fallido</string>
     <string name="str_voice_msg_play">reproducir mensaje de voz</string>
@@ -494,6 +503,9 @@
     <string name="fees_total">Total</string>
     <string name="str_page_up">Arriba</string>
     <string name="str_page_down">Abajo</string>
+    <string name="str_page_first">Primera página</string>
+    <string name="str_page_last">Última página</string>
+
 
     <string name="str_processing">Procesando…</string>
     <string name="str_recover">Recuperar</string>

+ 12 - 0
resource/src/main/res/values-ru/strings.xml

@@ -90,6 +90,7 @@
     <string name="server_config">Конфигурация сервера</string>
     <string name="product_desc">Продукт:</string>
     <string name="device_error">Ошибка устройства, перезагрузите компьютер!</string>
+
     <string name="str_voice_msg_start">Начать запись</string>
     <string name="str_voice_msg_started">Запись голоса</string>
     <string name="str_voice_msg_end">Конец</string>
@@ -97,6 +98,14 @@
     <string name="str_voice_msg_btn_text">Нажмите, чтобы записать сообщение</string>
     <string name="str_voice_msg_record_loss">слишком мало времени</string>
     <string name="str_voice_msg_record_cancel">Голосовое сообщение отменено</string>
+    <string name="str_empty_voice_msg">Нет голосового сообщения</string>
+    <string name="str_delete_tip">Удалить?</string>
+    <string name="str_message_content_error">Недействительное сообщение</string>
+    <string name="str_voice_message_invalid">Недействительное голосовое сообщение</string>
+    <string name="str_message_save_success">Успешно!</string>
+    <string name="str_record_message_success">Запись успешно завершена!</string>
+    <string name="str_invalid_creator_name">Пожалуйста, выберите создателя</string>
+
     <string name="str_voice_msg_send_success">успешная отправка</string>
     <string name="str_voice_msg_send_fail">отправить не удалось</string>
     <string name="str_voice_msg_play">воспроизвести голосовое сообщение</string>
@@ -478,6 +487,9 @@
     <string name="fees_total">Итого</string>
     <string name="str_page_up">Вверх</string>
     <string name="str_page_down">Вниз</string>
+    <string name="str_page_first">Первая страница</string>
+    <string name="str_page_last">Последняя страница</string>
+
 
     <string name="str_processing">Обработка...</string>
     <string name="str_recover">Восстановление</string>

+ 3 - 0
resource/src/main/res/values-zh/strings.xml

@@ -11,6 +11,7 @@
     <string name="group_message">群留言</string>
     <string name="reconnect">重连中</string>
 
+
     <string name="default_nurse_config_name">护理</string>
     <string name="str_empty">暂无</string>
     <string name="str_null">未知</string>
@@ -502,6 +503,8 @@
     <string name="fees_total">共计</string>
     <string name="str_page_up">上一页</string>
     <string name="str_page_down">下一页</string>
+    <string name="str_page_first">第一页</string>
+    <string name="str_page_last">末页</string>
 
     <string name="str_processing">处理中,请稍后…</string>
     <string name="str_recover">收回列表</string>

+ 12 - 1
resource/src/main/res/values/strings.xml

@@ -104,14 +104,22 @@
     <string name="server_config">Server config</string>
     <string name="product_desc">Product:</string>
     <string name="device_error">Device error, please reboot!</string>
-
     <string name="str_voice_msg_start">Start record</string>
     <string name="str_voice_msg_started">Voice recording</string>
     <string name="str_voice_msg_end">End</string>
+
     <string name="str_voice_msg_btn_title">Release to send message</string>
     <string name="str_voice_msg_btn_text">Press to record message</string>
     <string name="str_voice_msg_record_loss">time is too short</string>
     <string name="str_voice_msg_record_cancel">Voice msg canceled</string>
+    <string name="str_empty_voice_msg">No voice message</string>
+    <string name="str_delete_tip">Delete?</string>
+    <string name="str_message_content_error">Invalid message</string>
+    <string name="str_voice_message_invalid">Invalid voice message</string>
+    <string name="str_message_save_success">Success!</string>
+    <string name="str_record_message_success">Record success!</string>
+    <string name="str_invalid_creator_name">Please select creator</string>
+
     <string name="str_voice_msg_send_success">send success</string>
     <string name="str_voice_msg_send_fail">send failed</string>
     <string name="str_voice_msg_play">play voice msg</string>
@@ -493,6 +501,9 @@
     <string name="fees_total">Total</string>
     <string name="str_page_up">Up</string>
     <string name="str_page_down">Down</string>
+    <string name="str_page_first">First Page</string>
+    <string name="str_page_last">Last Page</string>
+
 
     <string name="str_processing">Processing…</string>
     <string name="str_recover">Recover</string>

+ 5 - 0
resource/src/main/res/values/styles.xml

@@ -35,5 +35,10 @@
     </style>
 
 
+    <style name="Theme.AppCompat.Translucent" parent="Theme.AppCompat.NoActionBar">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowTranslucentStatus">true</item>
+    </style>
 
 </resources>