diff --git a/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt b/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt index 56448d3..8d390be 100644 --- a/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt +++ b/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt @@ -1,5 +1,6 @@ package com.yuanxuan.rokid +import android.content.Intent import android.os.Bundle import android.view.KeyEvent import androidx.activity.addCallback @@ -11,9 +12,15 @@ import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.NavOptions +import androidx.navigation.fragment.NavHostFragment import com.yuanxuan.rokid.databinding.ActivityMainBinding import com.yuanxuan.rokid.extension.fadeIn import com.yuanxuan.rokid.extension.fadeOut +import com.yuanxuan.rokid.keeplive.KeepLiveService +import com.yuanxuan.rokid.network.websocket.WebSocketEvent +import com.yuanxuan.rokid.ui.NoticeFragment +import kotlinx.coroutines.delay import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { @@ -39,8 +46,33 @@ class MainActivity : AppCompatActivity() { /** * 拦截返回键事件,防止返回到桌面 */ - onBackPressedDispatcher.addCallback {} + onBackPressedDispatcher.addCallback { + viewModel.wakeUp() + navigationToast("TestMessage") + } + /** + * 这个服务保证心跳包准时发 + */ + val serviceIntent = Intent(this, KeepLiveService::class.java) + startForegroundService(serviceIntent) + /** + * 出路服务端事件 + */ + lifecycleScope.launch { + viewModel.socketEvent.collect { event -> + when (event) { + is WebSocketEvent.Notice -> { + viewModel.wakeUp() + delay(500) + navigationToast(event.msg) + } + + WebSocketEvent.Unknow -> {} + } + + } + } } @@ -55,6 +87,23 @@ class MainActivity : AppCompatActivity() { } } + private fun navigationToast(toast: String) { + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment + + val options = NavOptions.Builder() + .setEnterAnim(android.R.anim.fade_in) + .setExitAnim(android.R.anim.fade_out) + .setPopEnterAnim(android.R.anim.fade_in) + .setPopExitAnim(android.R.anim.fade_out) + .build() + val bundle = Bundle().apply { + putString(NoticeFragment.TOAST_MESSAGE, toast) + } + val navController = navHostFragment.navController + navController.navigate(R.id.notice_fragment, bundle, options) + } + private fun observer() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { diff --git a/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt b/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt index be6d557..70506fe 100644 --- a/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt +++ b/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt @@ -2,6 +2,7 @@ package com.yuanxuan.rokid import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.yuanxuan.rokid.dependencies.AppDependencies import com.yuanxuan.rokid.dependencies.AppDependencies.deviceServiceManager import com.yuanxuan.rokid.device.DeviceServiceManager import kotlinx.coroutines.flow.MutableSharedFlow @@ -37,7 +38,9 @@ class MainViewModel : ViewModel() { started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds), ) - fun quitInstructReceived(){ + val socketEvent = AppDependencies.webSocketManager.socketEventFlow + + fun quitInstructReceived() { deviceServiceManager.quitInstructReceived() } @@ -47,6 +50,14 @@ class MainViewModel : ViewModel() { } } + fun wakeUp() { + deviceServiceManager.wakeup() + } + + fun playTTS(tts: String) { + deviceServiceManager.playTTS(tts) + } + sealed interface KeyEvent { data object DpadRight : KeyEvent //前滑 data object DpadLeft : KeyEvent //后滑 diff --git a/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt b/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt index 5495fca..ef0b433 100644 --- a/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt +++ b/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt @@ -1,10 +1,8 @@ package com.yuanxuan.rokid import android.app.Application -import android.content.Intent import com.yuanxuan.rokid.dependencies.AppDependencies import com.yuanxuan.rokid.dependencies.ApplicationDependencyProvider -import com.yuanxuan.rokid.keeplive.KeepLiveService import com.yuanxuan.rokid.network.websocket.WebSocketReconnectWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -33,11 +31,6 @@ class RokidApplication : Application() { Timber.e(it) } } - /** - * 这个服务保证心跳包准时发 - */ - val serviceIntent = Intent(this, KeepLiveService::class.java) - startForegroundService(serviceIntent) } } \ No newline at end of file diff --git a/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt b/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt index 9a183ce..933d2e2 100644 --- a/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt +++ b/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt @@ -196,6 +196,13 @@ class DeviceServiceManager(val context: Application) : ConnectivityManager.Netwo _instructState.update { InstructState.None } } + + fun wakeup() { + systemFuncServiceTodo { service -> + service.wakeUp() + } + } + fun playTTS(msg: String) { ttsServiceTodo { ttsService?.playTtsMsg(msg) diff --git a/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt b/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt index 2332357..633b589 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt @@ -6,8 +6,8 @@ import java.net.NetworkInterface object NetUtils { -// fun getBaseUrl() = "http://${getLocalIPV4address()}.70:7070" - fun getBaseUrl() = "http://${getLocalIPV4address()}.52:8765" + fun getBaseUrl() = "http://${getLocalIPV4address()}.70:7070" +// fun getBaseUrl() = "http://${getLocalIPV4address()}.52:8765" /** diff --git a/app/src/main/java/com/yuanxuan/rokid/network/bean/WebSocketResponse.kt b/app/src/main/java/com/yuanxuan/rokid/network/bean/WebSocketResponse.kt new file mode 100644 index 0000000..b7899e1 --- /dev/null +++ b/app/src/main/java/com/yuanxuan/rokid/network/bean/WebSocketResponse.kt @@ -0,0 +1,22 @@ +package com.yuanxuan.rokid.network.bean + +import com.google.gson.JsonElement +import com.google.gson.annotations.SerializedName + +data class WebSocketResponse( + @SerializedName("MsgType") + val msgType: Int, + @SerializedName("Msg") + val msg: JsonElement +) { + + enum class MsgType(val value: Int) { + Notice(0); + + companion object { + fun fromValue(value: Int) = entries.firstOrNull { it.value == value } + } + + } + +} diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt index c720065..b995ac4 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt @@ -1,11 +1,17 @@ package com.yuanxuan.rokid.network.websocket +import com.google.gson.Gson import com.yuanxuan.rokid.network.NetUtils +import com.yuanxuan.rokid.network.bean.WebSocketResponse import com.yuanxuan.rokid.network.websocket.WebSocketConnection.Companion.DEFAULT_SEND_TIMEOUT import com.yuanxuan.rokid.network.websocket.WebSocketConnection.Companion.PING_INTERVAL_TIME +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response @@ -13,12 +19,16 @@ import okhttp3.WebSocket import okhttp3.WebSocketListener import timber.log.Timber -class OkHttpWebSocketConnection() : WebSocketListener(), WebSocketConnection { +class OkHttpWebSocketConnection(val scope: CoroutineScope) : WebSocketListener(), + WebSocketConnection { private val _webSocketConnectionStateFlow: MutableStateFlow = MutableStateFlow(WebSocketConnectionState.DISCONNECTED) val webSocketConnectionStateFlow = _webSocketConnectionStateFlow.asStateFlow() + private val _eventFlow = MutableSharedFlow() + val eventFlow = _eventFlow.asSharedFlow() + private var client: WebSocket? = null @Synchronized @@ -38,6 +48,20 @@ class OkHttpWebSocketConnection() : WebSocketListener(), WebSocketConnection { override fun onMessage(webSocket: WebSocket, text: String) { Timber.d(text) + val response = Gson().fromJson(text, WebSocketResponse::class.java) + val msgType = WebSocketResponse.MsgType.fromValue(response.msgType) + val event = when (msgType) { + WebSocketResponse.MsgType.Notice -> { + WebSocketEvent.Notice(response.msg.asString) + } + + null -> { + WebSocketEvent.Unknow + } + } + scope.launch { + _eventFlow.emit(event) + } } override fun onOpen(webSocket: WebSocket, response: Response) { diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketEvent.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketEvent.kt new file mode 100644 index 0000000..e8c06b0 --- /dev/null +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketEvent.kt @@ -0,0 +1,7 @@ +package com.yuanxuan.rokid.network.websocket + +sealed interface WebSocketEvent { + data class Notice(val msg: String) : WebSocketEvent + + data object Unknow : WebSocketEvent +} \ No newline at end of file diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt index bdf8c01..51770b9 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt @@ -7,7 +7,9 @@ import kotlinx.coroutines.launch class WebSocketManager(context: Context, scope: CoroutineScope) { - private val webSocketConnection = OkHttpWebSocketConnection() + private val webSocketConnection = OkHttpWebSocketConnection(scope = scope) + + val socketEventFlow = webSocketConnection.eventFlow init { scope.launch { diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt index e1621ab..de19096 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt @@ -2,23 +2,27 @@ package com.yuanxuan.rokid.network.websocket import android.content.Context import androidx.work.Constraints +import androidx.work.CoroutineWorker import androidx.work.ExistingWorkPolicy import androidx.work.NetworkType import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OutOfQuotaPolicy import androidx.work.WorkManager -import androidx.work.Worker import androidx.work.WorkerParameters import com.yuanxuan.rokid.dependencies.AppDependencies +import kotlinx.coroutines.delay import timber.log.Timber -class WebSocketReconnectWorker(context: Context, workerParams: WorkerParameters) : Worker( +class WebSocketReconnectWorker(context: Context, workerParams: WorkerParameters) : CoroutineWorker( context, workerParams ) { - override fun doWork(): Result { + override suspend fun doWork(): Result { + /** + * 第一次启动给点时间连wifi、重连等5s + */ + delay(5000) Timber.d("尝试开始重连") - AppDependencies.deviceServiceManager.playTTS("开始重连") AppDependencies.webSocketManager.connect(AppDependencies.deviceServiceManager.sn) return Result.success() } diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketResponseMessage.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketResponseMessage.kt deleted file mode 100644 index 7c88dcd..0000000 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketResponseMessage.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.yuanxuan.rokid.network.websocket - -import com.google.gson.annotations.SerializedName - -data class WebSocketResponseMessage( - @SerializedName("MsgType") - val msgType: Int, - @SerializedName("Msg") - val msg: T -) diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/NoticeFragment.kt b/app/src/main/java/com/yuanxuan/rokid/ui/NoticeFragment.kt new file mode 100644 index 0000000..cfbfe31 --- /dev/null +++ b/app/src/main/java/com/yuanxuan/rokid/ui/NoticeFragment.kt @@ -0,0 +1,38 @@ +package com.yuanxuan.rokid.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import com.yuanxuan.rokid.databinding.FragmentNoticeBinding + +class NoticeFragment : Fragment() { + + companion object { + const val TOAST_MESSAGE = "toast_message" + } + + private lateinit var binding: FragmentNoticeBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentNoticeBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val toast = arguments?.getString(TOAST_MESSAGE) + binding.toast.text = toast + } + + override fun onPause() { + super.onPause() + findNavController().navigateUp() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_notice.xml b/app/src/main/res/layout/fragment_notice.xml new file mode 100644 index 0000000..1785bf3 --- /dev/null +++ b/app/src/main/res/layout/fragment_notice.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_home.xml b/app/src/main/res/layout/item_home.xml index 73accc4..c01b21e 100644 --- a/app/src/main/res/layout/item_home.xml +++ b/app/src/main/res/layout/item_home.xml @@ -14,7 +14,7 @@ android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="#ffffff" + android:textColor="@color/white" android:textSize="10sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/navigation/app_navigation.xml b/app/src/main/res/navigation/app_navigation.xml index 8dedc9c..bfe8af1 100644 --- a/app/src/main/res/navigation/app_navigation.xml +++ b/app/src/main/res/navigation/app_navigation.xml @@ -39,4 +39,10 @@ android:label="sn" tools:layout="@layout/fragment_sn" /> + + \ No newline at end of file