diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt index 3676eab..725b743 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt @@ -27,7 +27,6 @@ import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.view.check.DisclosureActivity -import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.casic.br.operationsite.vm.LoginViewModel import com.casic.br.operationsite.vm.WorkSiteViewModel @@ -50,7 +49,6 @@ private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var deviceViewModel: DeviceViewModel private lateinit var loginViewModel: LoginViewModel - private lateinit var alarmViewModel: AlarmViewModel private lateinit var userHelmetCode: String private val polygonOptions by lazy { PolygonOptions() } private val latLngArray: MutableList = ArrayList() @@ -254,11 +252,6 @@ navigatePageTo() } } - - alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] - alarmViewModel.alarmState.observe(this) { - - } } override fun onMarkerClick(marker: Marker?): Boolean { @@ -394,15 +387,6 @@ navigatePageTo() } - binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> - val state = if (isChecked) { - "1" - } else { - "0" - } - alarmViewModel.changeAlarmState("", state) - } - binding.reloadDataView.setOnClickListener { aMap.clear() @@ -416,7 +400,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - alarmViewModel.getAlarmDetail(this, "") } override fun onPause() { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt index 3676eab..725b743 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt @@ -27,7 +27,6 @@ import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.view.check.DisclosureActivity -import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.casic.br.operationsite.vm.LoginViewModel import com.casic.br.operationsite.vm.WorkSiteViewModel @@ -50,7 +49,6 @@ private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var deviceViewModel: DeviceViewModel private lateinit var loginViewModel: LoginViewModel - private lateinit var alarmViewModel: AlarmViewModel private lateinit var userHelmetCode: String private val polygonOptions by lazy { PolygonOptions() } private val latLngArray: MutableList = ArrayList() @@ -254,11 +252,6 @@ navigatePageTo() } } - - alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] - alarmViewModel.alarmState.observe(this) { - - } } override fun onMarkerClick(marker: Marker?): Boolean { @@ -394,15 +387,6 @@ navigatePageTo() } - binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> - val state = if (isChecked) { - "1" - } else { - "0" - } - alarmViewModel.changeAlarmState("", state) - } - binding.reloadDataView.setOnClickListener { aMap.clear() @@ -416,7 +400,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - alarmViewModel.getAlarmDetail(this, "") } override fun onPause() { diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt index cec8a1f..50bb949 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt @@ -1,6 +1,5 @@ package com.casic.br.operationsite.view.check -import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle @@ -9,10 +8,10 @@ import android.util.Base64 import android.util.Log import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.R import com.casic.br.operationsite.databinding.ActivityEnvironmentBinding import com.casic.br.operationsite.extensions.initImmersionBar -import com.casic.br.operationsite.service.WebSocketMessageService import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.utils.tcp.ISocketListener @@ -28,25 +27,30 @@ import com.pengxh.kt.lite.utils.ActivityStackManager import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.Timer import java.util.TimerTask +import java.util.concurrent.TimeUnit class EnvironmentActivity : KotlinBaseActivity(), Handler.Callback { - companion object { - lateinit var weakReferenceHandler: WeakReferenceHandler - } - private val kTag = "EnvironmentActivity" private val context = this private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var constructionCheckViewModel: ConstructionCheckViewModel private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var timer: Timer - private var isStart = false + private lateinit var webSocket: WebSocket private var isFirstConfirm = false private var isSecondConfirm = false private var isThirdConfirm = false @@ -54,7 +58,7 @@ override fun handleMessage(msg: Message): Boolean { when (msg.what) { - LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "WebSocket连接成功".show(this) + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { try { @@ -68,7 +72,7 @@ } } - LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "WebSocket连接失败".show(this) + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) } return true } @@ -80,7 +84,6 @@ return@setOnClickListener } SocketManager.get.send(LocaleConstant.START_ENV_COMMAND) - isStart = true constructionCheckViewModel.setCurrentPhase(this, "before_operation_environment") //播放RTSP流 binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) @@ -131,13 +134,20 @@ } isThirdConfirm = true } + + binding.endEnvCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.END_ENV_COMMAND) + navigatePageTo() + } } override fun initOnCreate(savedInstanceState: Bundle?) { ActivityStackManager.addActivity(this) - startService(Intent(this, WebSocketMessageService::class.java)) - weakReferenceHandler = WeakReferenceHandler(this) constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] @@ -146,6 +156,8 @@ binding.videoView.start() } + startWebSocket() + timer = Timer() workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] timer.schedule(object : TimerTask() { @@ -178,6 +190,45 @@ } } + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@EnvironmentActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + override fun initViewBinding(): ActivityEnvironmentBinding { return ActivityEnvironmentBinding.inflate(layoutInflater) } @@ -203,5 +254,6 @@ super.onDestroy() binding.videoView.suspend() timer.cancel() + webSocket.close(1000, null) } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt index 3676eab..725b743 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt @@ -27,7 +27,6 @@ import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.view.check.DisclosureActivity -import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.casic.br.operationsite.vm.LoginViewModel import com.casic.br.operationsite.vm.WorkSiteViewModel @@ -50,7 +49,6 @@ private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var deviceViewModel: DeviceViewModel private lateinit var loginViewModel: LoginViewModel - private lateinit var alarmViewModel: AlarmViewModel private lateinit var userHelmetCode: String private val polygonOptions by lazy { PolygonOptions() } private val latLngArray: MutableList = ArrayList() @@ -254,11 +252,6 @@ navigatePageTo() } } - - alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] - alarmViewModel.alarmState.observe(this) { - - } } override fun onMarkerClick(marker: Marker?): Boolean { @@ -394,15 +387,6 @@ navigatePageTo() } - binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> - val state = if (isChecked) { - "1" - } else { - "0" - } - alarmViewModel.changeAlarmState("", state) - } - binding.reloadDataView.setOnClickListener { aMap.clear() @@ -416,7 +400,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - alarmViewModel.getAlarmDetail(this, "") } override fun onPause() { diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt index cec8a1f..50bb949 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt @@ -1,6 +1,5 @@ package com.casic.br.operationsite.view.check -import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle @@ -9,10 +8,10 @@ import android.util.Base64 import android.util.Log import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.R import com.casic.br.operationsite.databinding.ActivityEnvironmentBinding import com.casic.br.operationsite.extensions.initImmersionBar -import com.casic.br.operationsite.service.WebSocketMessageService import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.utils.tcp.ISocketListener @@ -28,25 +27,30 @@ import com.pengxh.kt.lite.utils.ActivityStackManager import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.Timer import java.util.TimerTask +import java.util.concurrent.TimeUnit class EnvironmentActivity : KotlinBaseActivity(), Handler.Callback { - companion object { - lateinit var weakReferenceHandler: WeakReferenceHandler - } - private val kTag = "EnvironmentActivity" private val context = this private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var constructionCheckViewModel: ConstructionCheckViewModel private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var timer: Timer - private var isStart = false + private lateinit var webSocket: WebSocket private var isFirstConfirm = false private var isSecondConfirm = false private var isThirdConfirm = false @@ -54,7 +58,7 @@ override fun handleMessage(msg: Message): Boolean { when (msg.what) { - LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "WebSocket连接成功".show(this) + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { try { @@ -68,7 +72,7 @@ } } - LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "WebSocket连接失败".show(this) + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) } return true } @@ -80,7 +84,6 @@ return@setOnClickListener } SocketManager.get.send(LocaleConstant.START_ENV_COMMAND) - isStart = true constructionCheckViewModel.setCurrentPhase(this, "before_operation_environment") //播放RTSP流 binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) @@ -131,13 +134,20 @@ } isThirdConfirm = true } + + binding.endEnvCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.END_ENV_COMMAND) + navigatePageTo() + } } override fun initOnCreate(savedInstanceState: Bundle?) { ActivityStackManager.addActivity(this) - startService(Intent(this, WebSocketMessageService::class.java)) - weakReferenceHandler = WeakReferenceHandler(this) constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] @@ -146,6 +156,8 @@ binding.videoView.start() } + startWebSocket() + timer = Timer() workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] timer.schedule(object : TimerTask() { @@ -178,6 +190,45 @@ } } + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@EnvironmentActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + override fun initViewBinding(): ActivityEnvironmentBinding { return ActivityEnvironmentBinding.inflate(layoutInflater) } @@ -203,5 +254,6 @@ super.onDestroy() binding.videoView.suspend() timer.cancel() + webSocket.close(1000, null) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt new file mode 100644 index 0000000..8805701 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt @@ -0,0 +1,270 @@ +package com.casic.br.operationsite.view.check + +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.Base64 +import android.util.Log +import android.view.View +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.casic.br.operationsite.R +import com.casic.br.operationsite.databinding.ActivityGuardiansBinding +import com.casic.br.operationsite.extensions.initImmersionBar +import com.casic.br.operationsite.utils.LocaleConstant +import com.casic.br.operationsite.utils.RuntimeCache +import com.casic.br.operationsite.view.BigImageActivity +import com.casic.br.operationsite.view.MainActivity +import com.casic.br.operationsite.vm.AlarmViewModel +import com.casic.br.operationsite.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.vm.WorkSiteViewModel +import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.saveImage +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.extensions.toJson +import com.pengxh.kt.lite.utils.ActivityStackManager +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.TimeUnit + +class GuardiansActivity : KotlinBaseActivity(), Handler.Callback { + + private val kTag = "GuardiansActivity" + private val context = this + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var alarmViewModel: AlarmViewModel + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel + private lateinit var workSiteViewModel: WorkSiteViewModel + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var webSocket: WebSocket + private lateinit var timer: Timer + private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private val marginOffset by lazy { 1.dp2px(this) } + private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 + + override fun initEvent() { + binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> + val state = if (isChecked) { + "1" + } else { + "0" + } + alarmViewModel.changeAlarmState("", state) + } + + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() + Log.d(kTag, region.toJson()) + + constructionCheckViewModel.setVideoRegion(this, region) + } + + binding.startVideoCheckButton.setOnClickListener { + constructionCheckViewModel.setCurrentPhase(this, "in_operation") + } + + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + "当前模式不支持手动添加图片".show(context) + } + + override fun onItemClick(position: Int) { + if (recyclerViewImages[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + navigatePageTo(position, recyclerViewImages) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + recyclerViewImages.removeAt(position) + imageAdapter.notifyDataSetChanged() + } + }) + + binding.endTaskButton.setOnClickListener { + AlertControlDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("确定结束此次施工?").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + ActivityStackManager.finishActivity(DisclosureActivity::class.java) + ActivityStackManager.finishActivity(EnvironmentActivity::class.java) + ActivityStackManager.finishActivity(SuppliesActivity::class.java) + navigatePageTo() + finish() + } + + override fun onCancelClick() {} + }).build().show() + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + ActivityStackManager.addActivity(this) + + weakReferenceHandler = WeakReferenceHandler(this) + //播放RTSP流 + binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) + binding.videoView.setOnPreparedListener { + binding.videoView.requestFocus() + binding.videoView.start() + } + startWebSocket() + + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] + alarmViewModel.alarmState.observe(this) { + + } + + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] + constructionCheckViewModel.postResult.observe(this) { + if (it.code == 200) { + "区域配置成功".show(this) + } + } + + //左右边距 + val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) + imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 3, 3) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + ) + binding.recyclerView.adapter = imageAdapter + + timer = Timer() + workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] + timer.schedule(object : TimerTask() { + override fun run() { + workSiteViewModel.getWorkers(context, RuntimeCache.projectId) + } + }, 0, 5000) + workSiteViewModel.workerResult.observe(this) { + if (it.code == 200) { + it.data.forEach { worker -> + if (worker.lat.isNotBlank() && worker.lng.isNotBlank()) { + val value = + "CO:${worker.co}ppm, CH4:${worker.gas}ppm, H2S:${worker.co}ppm, O2:${worker.o2}%VOL" + Log.d(kTag, "value: $value") + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + when (msg.what) { + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) + + LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { + try { + val bitmapArray = Base64.decode((msg.obj as String), Base64.DEFAULT) + val bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.size) + val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" + Log.d(kTag, "imagePath: $imagePath") + bitmap.saveImage(imagePath) + if (recyclerViewImages.size == 3) { + recyclerViewImages.removeAt(0) + } + recyclerViewImages.add(imagePath) + imageAdapter.notifyDataSetChanged() + } catch (e: Exception) { + e.printStackTrace() + } + } + + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) + } + return true + } + + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@GuardiansActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + + override fun initViewBinding(): ActivityGuardiansBinding { + return ActivityGuardiansBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun onResume() { + super.onResume() + alarmViewModel.getAlarmState(this) + } + + override fun onDestroy() { + super.onDestroy() + binding.videoView.suspend() + timer.cancel() + webSocket.close(1000, null) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt index 3676eab..725b743 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt @@ -27,7 +27,6 @@ import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.view.check.DisclosureActivity -import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.casic.br.operationsite.vm.LoginViewModel import com.casic.br.operationsite.vm.WorkSiteViewModel @@ -50,7 +49,6 @@ private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var deviceViewModel: DeviceViewModel private lateinit var loginViewModel: LoginViewModel - private lateinit var alarmViewModel: AlarmViewModel private lateinit var userHelmetCode: String private val polygonOptions by lazy { PolygonOptions() } private val latLngArray: MutableList = ArrayList() @@ -254,11 +252,6 @@ navigatePageTo() } } - - alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] - alarmViewModel.alarmState.observe(this) { - - } } override fun onMarkerClick(marker: Marker?): Boolean { @@ -394,15 +387,6 @@ navigatePageTo() } - binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> - val state = if (isChecked) { - "1" - } else { - "0" - } - alarmViewModel.changeAlarmState("", state) - } - binding.reloadDataView.setOnClickListener { aMap.clear() @@ -416,7 +400,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - alarmViewModel.getAlarmDetail(this, "") } override fun onPause() { diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt index cec8a1f..50bb949 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt @@ -1,6 +1,5 @@ package com.casic.br.operationsite.view.check -import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle @@ -9,10 +8,10 @@ import android.util.Base64 import android.util.Log import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.R import com.casic.br.operationsite.databinding.ActivityEnvironmentBinding import com.casic.br.operationsite.extensions.initImmersionBar -import com.casic.br.operationsite.service.WebSocketMessageService import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.utils.tcp.ISocketListener @@ -28,25 +27,30 @@ import com.pengxh.kt.lite.utils.ActivityStackManager import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.Timer import java.util.TimerTask +import java.util.concurrent.TimeUnit class EnvironmentActivity : KotlinBaseActivity(), Handler.Callback { - companion object { - lateinit var weakReferenceHandler: WeakReferenceHandler - } - private val kTag = "EnvironmentActivity" private val context = this private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var constructionCheckViewModel: ConstructionCheckViewModel private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var timer: Timer - private var isStart = false + private lateinit var webSocket: WebSocket private var isFirstConfirm = false private var isSecondConfirm = false private var isThirdConfirm = false @@ -54,7 +58,7 @@ override fun handleMessage(msg: Message): Boolean { when (msg.what) { - LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "WebSocket连接成功".show(this) + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { try { @@ -68,7 +72,7 @@ } } - LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "WebSocket连接失败".show(this) + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) } return true } @@ -80,7 +84,6 @@ return@setOnClickListener } SocketManager.get.send(LocaleConstant.START_ENV_COMMAND) - isStart = true constructionCheckViewModel.setCurrentPhase(this, "before_operation_environment") //播放RTSP流 binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) @@ -131,13 +134,20 @@ } isThirdConfirm = true } + + binding.endEnvCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.END_ENV_COMMAND) + navigatePageTo() + } } override fun initOnCreate(savedInstanceState: Bundle?) { ActivityStackManager.addActivity(this) - startService(Intent(this, WebSocketMessageService::class.java)) - weakReferenceHandler = WeakReferenceHandler(this) constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] @@ -146,6 +156,8 @@ binding.videoView.start() } + startWebSocket() + timer = Timer() workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] timer.schedule(object : TimerTask() { @@ -178,6 +190,45 @@ } } + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@EnvironmentActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + override fun initViewBinding(): ActivityEnvironmentBinding { return ActivityEnvironmentBinding.inflate(layoutInflater) } @@ -203,5 +254,6 @@ super.onDestroy() binding.videoView.suspend() timer.cancel() + webSocket.close(1000, null) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt new file mode 100644 index 0000000..8805701 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt @@ -0,0 +1,270 @@ +package com.casic.br.operationsite.view.check + +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.Base64 +import android.util.Log +import android.view.View +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.casic.br.operationsite.R +import com.casic.br.operationsite.databinding.ActivityGuardiansBinding +import com.casic.br.operationsite.extensions.initImmersionBar +import com.casic.br.operationsite.utils.LocaleConstant +import com.casic.br.operationsite.utils.RuntimeCache +import com.casic.br.operationsite.view.BigImageActivity +import com.casic.br.operationsite.view.MainActivity +import com.casic.br.operationsite.vm.AlarmViewModel +import com.casic.br.operationsite.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.vm.WorkSiteViewModel +import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.saveImage +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.extensions.toJson +import com.pengxh.kt.lite.utils.ActivityStackManager +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.TimeUnit + +class GuardiansActivity : KotlinBaseActivity(), Handler.Callback { + + private val kTag = "GuardiansActivity" + private val context = this + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var alarmViewModel: AlarmViewModel + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel + private lateinit var workSiteViewModel: WorkSiteViewModel + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var webSocket: WebSocket + private lateinit var timer: Timer + private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private val marginOffset by lazy { 1.dp2px(this) } + private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 + + override fun initEvent() { + binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> + val state = if (isChecked) { + "1" + } else { + "0" + } + alarmViewModel.changeAlarmState("", state) + } + + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() + Log.d(kTag, region.toJson()) + + constructionCheckViewModel.setVideoRegion(this, region) + } + + binding.startVideoCheckButton.setOnClickListener { + constructionCheckViewModel.setCurrentPhase(this, "in_operation") + } + + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + "当前模式不支持手动添加图片".show(context) + } + + override fun onItemClick(position: Int) { + if (recyclerViewImages[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + navigatePageTo(position, recyclerViewImages) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + recyclerViewImages.removeAt(position) + imageAdapter.notifyDataSetChanged() + } + }) + + binding.endTaskButton.setOnClickListener { + AlertControlDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("确定结束此次施工?").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + ActivityStackManager.finishActivity(DisclosureActivity::class.java) + ActivityStackManager.finishActivity(EnvironmentActivity::class.java) + ActivityStackManager.finishActivity(SuppliesActivity::class.java) + navigatePageTo() + finish() + } + + override fun onCancelClick() {} + }).build().show() + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + ActivityStackManager.addActivity(this) + + weakReferenceHandler = WeakReferenceHandler(this) + //播放RTSP流 + binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) + binding.videoView.setOnPreparedListener { + binding.videoView.requestFocus() + binding.videoView.start() + } + startWebSocket() + + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] + alarmViewModel.alarmState.observe(this) { + + } + + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] + constructionCheckViewModel.postResult.observe(this) { + if (it.code == 200) { + "区域配置成功".show(this) + } + } + + //左右边距 + val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) + imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 3, 3) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + ) + binding.recyclerView.adapter = imageAdapter + + timer = Timer() + workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] + timer.schedule(object : TimerTask() { + override fun run() { + workSiteViewModel.getWorkers(context, RuntimeCache.projectId) + } + }, 0, 5000) + workSiteViewModel.workerResult.observe(this) { + if (it.code == 200) { + it.data.forEach { worker -> + if (worker.lat.isNotBlank() && worker.lng.isNotBlank()) { + val value = + "CO:${worker.co}ppm, CH4:${worker.gas}ppm, H2S:${worker.co}ppm, O2:${worker.o2}%VOL" + Log.d(kTag, "value: $value") + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + when (msg.what) { + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) + + LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { + try { + val bitmapArray = Base64.decode((msg.obj as String), Base64.DEFAULT) + val bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.size) + val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" + Log.d(kTag, "imagePath: $imagePath") + bitmap.saveImage(imagePath) + if (recyclerViewImages.size == 3) { + recyclerViewImages.removeAt(0) + } + recyclerViewImages.add(imagePath) + imageAdapter.notifyDataSetChanged() + } catch (e: Exception) { + e.printStackTrace() + } + } + + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) + } + return true + } + + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@GuardiansActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + + override fun initViewBinding(): ActivityGuardiansBinding { + return ActivityGuardiansBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun onResume() { + super.onResume() + alarmViewModel.getAlarmState(this) + } + + override fun onDestroy() { + super.onDestroy() + binding.videoView.suspend() + timer.cancel() + webSocket.close(1000, null) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt new file mode 100644 index 0000000..ba387fc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt @@ -0,0 +1,233 @@ +package com.casic.br.operationsite.view.check + +import android.content.Intent +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.Base64 +import android.util.Log +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.casic.br.operationsite.R +import com.casic.br.operationsite.databinding.ActivitySuppliesBinding +import com.casic.br.operationsite.extensions.initImmersionBar +import com.casic.br.operationsite.utils.LocaleConstant +import com.casic.br.operationsite.utils.tcp.ISocketListener +import com.casic.br.operationsite.utils.tcp.SocketManager +import com.casic.br.operationsite.view.BigImageActivity +import com.casic.br.operationsite.view.HelmetVideoActivity +import com.casic.br.operationsite.vm.ConstructionCheckViewModel +import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.saveImage +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.ActivityStackManager +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.concurrent.TimeUnit + +class SuppliesActivity : KotlinBaseActivity(), Handler.Callback { + + private val kTag = "SuppliesActivity" + private val context = this + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var webSocket: WebSocket + private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private val marginOffset by lazy { 1.dp2px(this) } + private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 + + override fun initEvent() { + binding.startSuppliesCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.START_SUPPLIES_COMMAND) + } + + binding.startVideoCheckButton.setOnClickListener { + startVideoLauncher.launch(Intent(this, HelmetVideoActivity::class.java)) + } + + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + "当前模式不支持手动添加图片".show(context) + } + + override fun onItemClick(position: Int) { + if (recyclerViewImages[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + navigatePageTo(position, recyclerViewImages) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + recyclerViewImages.removeAt(position) + imageAdapter.notifyDataSetChanged() + } + }) + } + + private val startVideoLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + Log.d(kTag, "startVideoLauncher: ") + SocketManager.get.send(LocaleConstant.START_VIDEO_COMMAND) + constructionCheckViewModel.setCurrentPhase(this, "before_operation_protection") + //播放RTSP流 + binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) + } + + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@SuppliesActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + ActivityStackManager.addActivity(this) + + weakReferenceHandler = WeakReferenceHandler(this) + constructionCheckViewModel = + ViewModelProvider(this)[ConstructionCheckViewModel::class.java] + + startWebSocket() + + binding.videoView.setOnPreparedListener { + binding.videoView.requestFocus() + binding.videoView.start() + } + + //左右边距 + val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) + imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 6, 3) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + ) + binding.recyclerView.adapter = imageAdapter + } + + override fun handleMessage(msg: Message): Boolean { + when (msg.what) { + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) + + LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { + try { + val bitmapArray = Base64.decode((msg.obj as String), Base64.DEFAULT) + val bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.size) + val imagePath = + "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" + Log.d(kTag, "imagePath: $imagePath") + bitmap.saveImage(imagePath) + recyclerViewImages.add(imagePath) + imageAdapter.notifyDataSetChanged() + + if (recyclerViewImages.size == 6) { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("检测到施工前劳保用品准备完毕,是否开始施工?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + navigatePageTo() + } + + override fun onCancelClick() {} + }).build().show() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) + } + return true + } + + override fun initViewBinding(): ActivitySuppliesBinding { + return ActivitySuppliesBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + binding.videoView.suspend() + webSocket.close(1000, null) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7e82efe..7bce4f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ + @@ -94,7 +95,6 @@ - diff --git a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt b/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt deleted file mode 100644 index 52e08a8..0000000 --- a/app/src/main/java/com/casic/br/operationsite/service/WebSocketMessageService.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.casic.br.operationsite.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.lifecycle.lifecycleScope -import com.casic.br.operationsite.utils.LocaleConstant -import com.casic.br.operationsite.view.check.EnvironmentActivity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import java.util.concurrent.TimeUnit - - -class WebSocketMessageService : Service(), LifecycleOwner { - - private val kTag = "WebSocketMessageService" - private val registry = LifecycleRegistry(this) - - override fun getLifecycle(): Lifecycle { - return registry - } - - private var webSocket: WebSocket? = null - - override fun onCreate() { - super.onCreate() - Log.d(kTag, "onCreate: WebSocketMessageService") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - //初始化WebSocket - val httpClient = OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .build() - lifecycleScope.launch(Dispatchers.IO) { - val request = Request.Builder() - .url("ws://192.168.10.142:8765") - .build() - httpClient.newWebSocket(request, object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - super.onOpen(webSocket, response) - this@WebSocketMessageService.webSocket = webSocket - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) - } - } - - override fun onMessage(webSocket: WebSocket, text: String) { - super.onMessage(webSocket, text) -// text.writeToFile(createLogFile()) - Log.d(kTag, "onMessage: ${text.length}") - lifecycleScope.launch(Dispatchers.Main) { - val message = EnvironmentActivity.weakReferenceHandler.obtainMessage() - message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE - message.obj = text - EnvironmentActivity.weakReferenceHandler.sendMessage(message) - } - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - super.onFailure(webSocket, t, response) - lifecycleScope.launch(Dispatchers.Main) { - EnvironmentActivity.weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) - } - } - }) - httpClient.dispatcher.executorService.shutdown() - } - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - webSocket?.close(1000, null) - Log.d(kTag, "onDestroy: WebSocketMessageService") - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt index 3676eab..725b743 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt @@ -27,7 +27,6 @@ import com.casic.br.operationsite.utils.DeviceType import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.view.check.DisclosureActivity -import com.casic.br.operationsite.vm.AlarmViewModel import com.casic.br.operationsite.vm.DeviceViewModel import com.casic.br.operationsite.vm.LoginViewModel import com.casic.br.operationsite.vm.WorkSiteViewModel @@ -50,7 +49,6 @@ private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var deviceViewModel: DeviceViewModel private lateinit var loginViewModel: LoginViewModel - private lateinit var alarmViewModel: AlarmViewModel private lateinit var userHelmetCode: String private val polygonOptions by lazy { PolygonOptions() } private val latLngArray: MutableList = ArrayList() @@ -254,11 +252,6 @@ navigatePageTo() } } - - alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] - alarmViewModel.alarmState.observe(this) { - - } } override fun onMarkerClick(marker: Marker?): Boolean { @@ -394,15 +387,6 @@ navigatePageTo() } - binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> - val state = if (isChecked) { - "1" - } else { - "0" - } - alarmViewModel.changeAlarmState("", state) - } - binding.reloadDataView.setOnClickListener { aMap.clear() @@ -416,7 +400,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - alarmViewModel.getAlarmDetail(this, "") } override fun onPause() { diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt index cec8a1f..50bb949 100644 --- a/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/view/check/EnvironmentActivity.kt @@ -1,6 +1,5 @@ package com.casic.br.operationsite.view.check -import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle @@ -9,10 +8,10 @@ import android.util.Base64 import android.util.Log import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.R import com.casic.br.operationsite.databinding.ActivityEnvironmentBinding import com.casic.br.operationsite.extensions.initImmersionBar -import com.casic.br.operationsite.service.WebSocketMessageService import com.casic.br.operationsite.utils.LocaleConstant import com.casic.br.operationsite.utils.RuntimeCache import com.casic.br.operationsite.utils.tcp.ISocketListener @@ -28,25 +27,30 @@ import com.pengxh.kt.lite.utils.ActivityStackManager import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.Timer import java.util.TimerTask +import java.util.concurrent.TimeUnit class EnvironmentActivity : KotlinBaseActivity(), Handler.Callback { - companion object { - lateinit var weakReferenceHandler: WeakReferenceHandler - } - private val kTag = "EnvironmentActivity" private val context = this private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var constructionCheckViewModel: ConstructionCheckViewModel private lateinit var workSiteViewModel: WorkSiteViewModel private lateinit var timer: Timer - private var isStart = false + private lateinit var webSocket: WebSocket private var isFirstConfirm = false private var isSecondConfirm = false private var isThirdConfirm = false @@ -54,7 +58,7 @@ override fun handleMessage(msg: Message): Boolean { when (msg.what) { - LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "WebSocket连接成功".show(this) + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { try { @@ -68,7 +72,7 @@ } } - LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "WebSocket连接失败".show(this) + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) } return true } @@ -80,7 +84,6 @@ return@setOnClickListener } SocketManager.get.send(LocaleConstant.START_ENV_COMMAND) - isStart = true constructionCheckViewModel.setCurrentPhase(this, "before_operation_environment") //播放RTSP流 binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) @@ -131,13 +134,20 @@ } isThirdConfirm = true } + + binding.endEnvCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.END_ENV_COMMAND) + navigatePageTo() + } } override fun initOnCreate(savedInstanceState: Bundle?) { ActivityStackManager.addActivity(this) - startService(Intent(this, WebSocketMessageService::class.java)) - weakReferenceHandler = WeakReferenceHandler(this) constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] @@ -146,6 +156,8 @@ binding.videoView.start() } + startWebSocket() + timer = Timer() workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] timer.schedule(object : TimerTask() { @@ -178,6 +190,45 @@ } } + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@EnvironmentActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + override fun initViewBinding(): ActivityEnvironmentBinding { return ActivityEnvironmentBinding.inflate(layoutInflater) } @@ -203,5 +254,6 @@ super.onDestroy() binding.videoView.suspend() timer.cancel() + webSocket.close(1000, null) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt new file mode 100644 index 0000000..8805701 --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/view/check/GuardiansActivity.kt @@ -0,0 +1,270 @@ +package com.casic.br.operationsite.view.check + +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.Base64 +import android.util.Log +import android.view.View +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.casic.br.operationsite.R +import com.casic.br.operationsite.databinding.ActivityGuardiansBinding +import com.casic.br.operationsite.extensions.initImmersionBar +import com.casic.br.operationsite.utils.LocaleConstant +import com.casic.br.operationsite.utils.RuntimeCache +import com.casic.br.operationsite.view.BigImageActivity +import com.casic.br.operationsite.view.MainActivity +import com.casic.br.operationsite.vm.AlarmViewModel +import com.casic.br.operationsite.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.vm.WorkSiteViewModel +import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.saveImage +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.extensions.toJson +import com.pengxh.kt.lite.utils.ActivityStackManager +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.TimeUnit + +class GuardiansActivity : KotlinBaseActivity(), Handler.Callback { + + private val kTag = "GuardiansActivity" + private val context = this + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var alarmViewModel: AlarmViewModel + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel + private lateinit var workSiteViewModel: WorkSiteViewModel + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var webSocket: WebSocket + private lateinit var timer: Timer + private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private val marginOffset by lazy { 1.dp2px(this) } + private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 + + override fun initEvent() { + binding.alarmCheckbox.setOnCheckedChangeListener { _, isChecked -> + val state = if (isChecked) { + "1" + } else { + "0" + } + alarmViewModel.changeAlarmState("", state) + } + + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() + Log.d(kTag, region.toJson()) + + constructionCheckViewModel.setVideoRegion(this, region) + } + + binding.startVideoCheckButton.setOnClickListener { + constructionCheckViewModel.setCurrentPhase(this, "in_operation") + } + + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + "当前模式不支持手动添加图片".show(context) + } + + override fun onItemClick(position: Int) { + if (recyclerViewImages[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + navigatePageTo(position, recyclerViewImages) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + recyclerViewImages.removeAt(position) + imageAdapter.notifyDataSetChanged() + } + }) + + binding.endTaskButton.setOnClickListener { + AlertControlDialog.Builder().setContext(this).setTitle("温馨提示") + .setMessage("确定结束此次施工?").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + ActivityStackManager.finishActivity(DisclosureActivity::class.java) + ActivityStackManager.finishActivity(EnvironmentActivity::class.java) + ActivityStackManager.finishActivity(SuppliesActivity::class.java) + navigatePageTo() + finish() + } + + override fun onCancelClick() {} + }).build().show() + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + ActivityStackManager.addActivity(this) + + weakReferenceHandler = WeakReferenceHandler(this) + //播放RTSP流 + binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) + binding.videoView.setOnPreparedListener { + binding.videoView.requestFocus() + binding.videoView.start() + } + startWebSocket() + + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] + alarmViewModel.alarmState.observe(this) { + + } + + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] + constructionCheckViewModel.postResult.observe(this) { + if (it.code == 200) { + "区域配置成功".show(this) + } + } + + //左右边距 + val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) + imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 3, 3) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + ) + binding.recyclerView.adapter = imageAdapter + + timer = Timer() + workSiteViewModel = ViewModelProvider(this)[WorkSiteViewModel::class.java] + timer.schedule(object : TimerTask() { + override fun run() { + workSiteViewModel.getWorkers(context, RuntimeCache.projectId) + } + }, 0, 5000) + workSiteViewModel.workerResult.observe(this) { + if (it.code == 200) { + it.data.forEach { worker -> + if (worker.lat.isNotBlank() && worker.lng.isNotBlank()) { + val value = + "CO:${worker.co}ppm, CH4:${worker.gas}ppm, H2S:${worker.co}ppm, O2:${worker.o2}%VOL" + Log.d(kTag, "value: $value") + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + when (msg.what) { + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) + + LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { + try { + val bitmapArray = Base64.decode((msg.obj as String), Base64.DEFAULT) + val bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.size) + val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" + Log.d(kTag, "imagePath: $imagePath") + bitmap.saveImage(imagePath) + if (recyclerViewImages.size == 3) { + recyclerViewImages.removeAt(0) + } + recyclerViewImages.add(imagePath) + imageAdapter.notifyDataSetChanged() + } catch (e: Exception) { + e.printStackTrace() + } + } + + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) + } + return true + } + + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@GuardiansActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + + override fun initViewBinding(): ActivityGuardiansBinding { + return ActivityGuardiansBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun onResume() { + super.onResume() + alarmViewModel.getAlarmState(this) + } + + override fun onDestroy() { + super.onDestroy() + binding.videoView.suspend() + timer.cancel() + webSocket.close(1000, null) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt new file mode 100644 index 0000000..ba387fc --- /dev/null +++ b/app/src/main/java/com/casic/br/operationsite/view/check/SuppliesActivity.kt @@ -0,0 +1,233 @@ +package com.casic.br.operationsite.view.check + +import android.content.Intent +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.Base64 +import android.util.Log +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.casic.br.operationsite.R +import com.casic.br.operationsite.databinding.ActivitySuppliesBinding +import com.casic.br.operationsite.extensions.initImmersionBar +import com.casic.br.operationsite.utils.LocaleConstant +import com.casic.br.operationsite.utils.tcp.ISocketListener +import com.casic.br.operationsite.utils.tcp.SocketManager +import com.casic.br.operationsite.view.BigImageActivity +import com.casic.br.operationsite.view.HelmetVideoActivity +import com.casic.br.operationsite.vm.ConstructionCheckViewModel +import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.saveImage +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.ActivityStackManager +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.concurrent.TimeUnit + +class SuppliesActivity : KotlinBaseActivity(), Handler.Callback { + + private val kTag = "SuppliesActivity" + private val context = this + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var webSocket: WebSocket + private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } + private val marginOffset by lazy { 1.dp2px(this) } + private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 + + override fun initEvent() { + binding.startSuppliesCheckButton.setOnClickListener { + if (SocketManager.get.statusCode != ISocketListener.STATUS_CONNECT_SUCCESS) { + "指令发送失败,请确认是否处于同一网段".show(this) + return@setOnClickListener + } + SocketManager.get.send(LocaleConstant.START_SUPPLIES_COMMAND) + } + + binding.startVideoCheckButton.setOnClickListener { + startVideoLauncher.launch(Intent(this, HelmetVideoActivity::class.java)) + } + + imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { + override fun onAddImageClick() { + "当前模式不支持手动添加图片".show(context) + } + + override fun onItemClick(position: Int) { + if (recyclerViewImages[position].isEmpty()) { + "图片加载失败,无法查看大图".show(context) + } else { + navigatePageTo(position, recyclerViewImages) + } + } + + override fun onItemLongClick(view: View?, position: Int) { + recyclerViewImages.removeAt(position) + imageAdapter.notifyDataSetChanged() + } + }) + } + + private val startVideoLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + Log.d(kTag, "startVideoLauncher: ") + SocketManager.get.send(LocaleConstant.START_VIDEO_COMMAND) + constructionCheckViewModel.setCurrentPhase(this, "before_operation_protection") + //播放RTSP流 + binding.videoView.setVideoURI(Uri.parse("rtsp://192.168.10.137:554")) + } + + private fun startWebSocket() { + //初始化WebSocket + val httpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() + lifecycleScope.launch(Dispatchers.IO) { + val request = Request.Builder().url("ws://192.168.10.142:8765").build() + httpClient.newWebSocket(request, object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + super.onOpen(webSocket, response) + this@SuppliesActivity.webSocket = webSocket + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_CONNECTED_CODE) + } + } + + override fun onMessage(webSocket: WebSocket, text: String) { + super.onMessage(webSocket, text) + lifecycleScope.launch(Dispatchers.Main) { + val message = weakReferenceHandler.obtainMessage() + message.what = LocaleConstant.WEBSOCKET_MESSAGE_CODE + message.obj = text + weakReferenceHandler.sendMessage(message) + } + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + super.onFailure(webSocket, t, response) + lifecycleScope.launch(Dispatchers.Main) { + weakReferenceHandler.sendEmptyMessage(LocaleConstant.WEBSOCKET_DISCONNECTED_CODE) + } + } + }) + httpClient.dispatcher.executorService.shutdown() + } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + ActivityStackManager.addActivity(this) + + weakReferenceHandler = WeakReferenceHandler(this) + constructionCheckViewModel = + ViewModelProvider(this)[ConstructionCheckViewModel::class.java] + + startWebSocket() + + binding.videoView.setOnPreparedListener { + binding.videoView.requestFocus() + binding.videoView.start() + } + + //左右边距 + val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) + imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 6, 3) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + ) + binding.recyclerView.adapter = imageAdapter + } + + override fun handleMessage(msg: Message): Boolean { + when (msg.what) { + LocaleConstant.WEBSOCKET_CONNECTED_CODE -> "AI连接成功".show(this) + + LocaleConstant.WEBSOCKET_MESSAGE_CODE -> { + try { + val bitmapArray = Base64.decode((msg.obj as String), Base64.DEFAULT) + val bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.size) + val imagePath = + "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" + Log.d(kTag, "imagePath: $imagePath") + bitmap.saveImage(imagePath) + recyclerViewImages.add(imagePath) + imageAdapter.notifyDataSetChanged() + + if (recyclerViewImages.size == 6) { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("检测到施工前劳保用品准备完毕,是否开始施工?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + navigatePageTo() + } + + override fun onCancelClick() {} + }).build().show() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + LocaleConstant.WEBSOCKET_DISCONNECTED_CODE -> "AI连接失败".show(this) + } + return true + } + + override fun initViewBinding(): ActivitySuppliesBinding { + return ActivitySuppliesBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + binding.videoView.suspend() + webSocket.close(1000, null) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_guardians.xml b/app/src/main/res/layout/activity_guardians.xml new file mode 100644 index 0000000..5403809 --- /dev/null +++ b/app/src/main/res/layout/activity_guardians.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + +