|
|
@@ -5,6 +5,8 @@ import android.media.AudioAttributes
|
|
|
import android.media.AudioManager
|
|
|
import android.media.MediaPlayer
|
|
|
import android.os.Build
|
|
|
+import android.os.Handler
|
|
|
+import android.os.Looper
|
|
|
import android.os.Vibrator
|
|
|
import androidx.fragment.app.FragmentActivity
|
|
|
import com.adealink.frame.aab.util.getCompatString
|
|
|
@@ -19,34 +21,48 @@ import com.adealink.weparty.call.R
|
|
|
import com.adealink.weparty.call.constant.TAG_CALL_MATCH_MODE
|
|
|
import com.adealink.weparty.call.data.CallMatchCancelRequest
|
|
|
import com.adealink.weparty.call.data.CallMatchReqAnswer
|
|
|
-import com.adealink.weparty.call.data.CallMatchReqAsk
|
|
|
import com.adealink.weparty.call.data.CallMatchResultNotify
|
|
|
import com.adealink.weparty.call.data.CallMatchResultNotifyAck
|
|
|
import com.adealink.weparty.call.data.CommonRequest
|
|
|
import com.adealink.weparty.call.manager.callManager
|
|
|
+import com.adealink.weparty.call.view.floatview.matchnotify.MatchFloatView
|
|
|
+import com.adealink.weparty.call.view.floatview.matchnotify.MatchFloatWindowData
|
|
|
+import com.adealink.weparty.call.view.floatview.matchnotify.MatchFloatWindowView
|
|
|
+import com.adealink.weparty.call.view.floatview.matchnotify.MatchNotificationView
|
|
|
import com.adealink.weparty.call.view.floatview.matchnotify.MatchNotifyFloatData
|
|
|
-import com.adealink.weparty.call.view.floatview.matchnotify.MatchNotifyFloatView
|
|
|
import com.adealink.weparty.commonui.toast.util.showFailedToast
|
|
|
import com.adealink.weparty.commonui.toast.util.showToast
|
|
|
import com.adealink.weparty.commonui.widget.CommonDialog
|
|
|
import com.adealink.weparty.commonui.widget.floatview.data.MODE_APPLICATION
|
|
|
+import com.adealink.weparty.commonui.widget.floatview.data.MODE_SYSTEM
|
|
|
import com.adealink.weparty.match.AnswerType
|
|
|
import com.adealink.weparty.match.MatchEvent
|
|
|
import com.adealink.weparty.match.MatchResult
|
|
|
import com.adealink.weparty.match.MatchStateMachine
|
|
|
import com.adealink.weparty.match.MatchTimeoutCallback
|
|
|
+import com.adealink.weparty.module.call.data.ACCEPT_FAIL
|
|
|
import com.adealink.weparty.module.call.data.CallType
|
|
|
import com.adealink.weparty.module.call.data.CallerSource
|
|
|
+import com.adealink.weparty.module.call.data.MATCH_CALL_TIME_OUT
|
|
|
+import com.adealink.weparty.module.call.data.MATCH_FAIL
|
|
|
+import com.adealink.weparty.module.call.data.MATCH_PEER_NOT_SELF
|
|
|
+import com.adealink.weparty.module.call.data.REJECT_FAIL
|
|
|
+import com.adealink.weparty.module.call.data.REJECT_SUCCESS
|
|
|
+import com.adealink.weparty.module.call.data.TIMEOUT_FAIL
|
|
|
+import com.adealink.weparty.module.call.data.TIMEOUT_SUCCESS
|
|
|
import com.adealink.weparty.module.call.match.IMatchListener
|
|
|
import com.adealink.weparty.module.call.match.IMatchManager
|
|
|
+import com.adealink.weparty.module.call.match.IMatchNotify
|
|
|
+import com.adealink.weparty.module.call.match.data.CallMatchReqAsk
|
|
|
import com.adealink.weparty.module.network.data.ServerCode
|
|
|
import com.adealink.weparty.module.profile.ProfileModule
|
|
|
import com.adealink.weparty.module.wallet.WalletModule
|
|
|
import com.adealink.weparty.module.wallet.data.Currency
|
|
|
import com.tencent.cloud.tuikit.engine.call.TUICallDefine
|
|
|
+import com.tencent.qcloud.tuicore.permission.PermissionRequester
|
|
|
import com.tencent.qcloud.tuikit.tuicallkit.state.TUICallState
|
|
|
+import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils
|
|
|
import com.tencent.qcloud.tuikit.tuicallkit.utils.PermissionRequest
|
|
|
-import kotlinx.coroutines.delay
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
|
|
|
|
|
@@ -65,7 +81,14 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
private var matchId = 0L
|
|
|
private var roomId = 0L
|
|
|
private var callMode = CallType.Voice.type
|
|
|
- private var matchNotifyFloatView: MatchNotifyFloatView? = null
|
|
|
+ private var matchNotifyFloatView: IMatchNotify? = null
|
|
|
+ private val mainHandler = Handler(Looper.getMainLooper())
|
|
|
+
|
|
|
+ private val callTimeout = Runnable {
|
|
|
+ if(TUICallState.instance.selfUser.get().callStatus.get() == TUICallDefine.Status.None) {
|
|
|
+ clearData(MATCH_CALL_TIME_OUT)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private val stateMachine = MatchStateMachine.instance
|
|
|
private val matchHttpService by lazy {
|
|
|
@@ -87,19 +110,21 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "CallMatchResultNotify onNotify: $data")
|
|
|
if (data.matchId == matchId && data.matchResult == MatchResult.SUCCESS.value) {
|
|
|
if (data.fromUid == ProfileModule.getMyUid()) {
|
|
|
- stateMachine.handleEvent(MatchEvent.MATCH_SUCCESS)
|
|
|
- callMode = data.callMode
|
|
|
- callManager.call(
|
|
|
- data.peerUid,
|
|
|
- TUICallDefine.MediaType.Video,
|
|
|
- CallerSource.CALLER,
|
|
|
- null,
|
|
|
- true,
|
|
|
- matchId
|
|
|
- )
|
|
|
+ if(stateMachine.handleEvent(MatchEvent.MATCH_SUCCESS)) {
|
|
|
+ callMode = data.callMode
|
|
|
+ Log.i(TAG_CALL_MATCH_MODE, "callManager call")
|
|
|
+ callManager.call(
|
|
|
+ data.peerUid,
|
|
|
+ TUICallDefine.MediaType.Video,
|
|
|
+ CallerSource.CALLER,
|
|
|
+ null,
|
|
|
+ true,
|
|
|
+ matchId
|
|
|
+ )
|
|
|
+ }
|
|
|
} else if (data.peerUid != ProfileModule.getMyUid()) {
|
|
|
//matchResult为1,说明fromUid和peerUid匹配成功,但不一定是自己
|
|
|
- clearData()
|
|
|
+ clearData(MATCH_PEER_NOT_SELF)
|
|
|
stopVibrateAndRing()
|
|
|
matchNotifyFloatView?.cancelNotifyView()
|
|
|
matchNotifyFloatView = null
|
|
|
@@ -108,7 +133,7 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
//走accept的回包
|
|
|
}
|
|
|
} else {
|
|
|
- clearData()
|
|
|
+ clearData(MATCH_FAIL)
|
|
|
stopVibrateAndRing()
|
|
|
matchNotifyFloatView?.cancelNotifyView()
|
|
|
matchNotifyFloatView = null
|
|
|
@@ -134,11 +159,17 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
stateMachine.handleEvent(MatchEvent.RECEIVE_REQUEST)
|
|
|
vibrate()
|
|
|
startRing(R.raw.phone_ringing)
|
|
|
- launch(Dispatcher.UI) {
|
|
|
- matchNotifyFloatView =
|
|
|
- MatchNotifyFloatView(MatchNotifyFloatData(MODE_APPLICATION)).apply {
|
|
|
- showNotifyView(data.userInfo, data.matchTimeout)
|
|
|
- }
|
|
|
+ val isForeground = DeviceUtils.isAppRunningForeground(AppUtil.appContext)
|
|
|
+ Log.d(TAG_CALL_MATCH_MODE, "isAppRunningForeground: $isForeground")
|
|
|
+ if(isForeground) {
|
|
|
+ launch(Dispatcher.UI) {
|
|
|
+ matchNotifyFloatView =
|
|
|
+ MatchFloatView(MatchNotifyFloatData(MODE_APPLICATION)).apply {
|
|
|
+ showNotifyView(data.userInfo, data.matchTimeout, data.matchId)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ handleInBackground(data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -243,10 +274,7 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "resultAck success")
|
|
|
stateMachine.handleEvent(MatchEvent.MATCH_SUCCESS)
|
|
|
//检查通话状态,10s后没接通电话,清除数据;男性拨打电话之后,女性是Waiting或者Accept状态
|
|
|
- delay(10_000)
|
|
|
- if(TUICallState.instance.selfUser.get().callStatus.get() == TUICallDefine.Status.None) {
|
|
|
- clearData()
|
|
|
- }
|
|
|
+ mainHandler.postDelayed(callTimeout, 10_000)
|
|
|
}
|
|
|
|
|
|
is Rlt.Failed -> {
|
|
|
@@ -257,7 +285,13 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- override fun accept() {
|
|
|
+ override fun accept(matchId: Long?) {
|
|
|
+ if (matchId != null && matchId != 0L) {
|
|
|
+ this.matchId = matchId
|
|
|
+ Log.i(TAG_CALL_MATCH_MODE, "accept, matchId: $matchId")
|
|
|
+ }
|
|
|
+ matchNotifyFloatView?.cancelNotifyView()
|
|
|
+ matchNotifyFloatView = null
|
|
|
stopVibrateAndRing()
|
|
|
if (!stateMachine.canHandleEvent(MatchEvent.ACCEPT_REQUEST)) {
|
|
|
Log.i(
|
|
|
@@ -270,7 +304,7 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
launch {
|
|
|
when (val rlt = matchHttpService.matchAnswer(
|
|
|
CallMatchReqAnswer(
|
|
|
- matchId,
|
|
|
+ this@MatchManager.matchId,
|
|
|
ProfileModule.getMyUid(),
|
|
|
AnswerType.ACCEPT.value
|
|
|
)
|
|
|
@@ -278,7 +312,7 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
is Rlt.Success -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "accept success")
|
|
|
// 等待状态更新完成后再调用resultAck
|
|
|
- val eventHandled = stateMachine.handleEventAsync(MatchEvent.ACCEPT_REQUEST)
|
|
|
+ val eventHandled = stateMachine.handleEvent(MatchEvent.ACCEPT_REQUEST)
|
|
|
if (eventHandled) {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "State updated, calling resultAck")
|
|
|
matchManager.resultAck()
|
|
|
@@ -288,13 +322,15 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
is Rlt.Failed -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "accept failed, ${rlt.error}")
|
|
|
stateMachine.handleEvent(MatchEvent.MATCH_TIMEOUT)
|
|
|
- clearData()
|
|
|
+ clearData(ACCEPT_FAIL)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
override fun reject() {
|
|
|
+ matchNotifyFloatView?.cancelNotifyView()
|
|
|
+ matchNotifyFloatView = null
|
|
|
stopVibrateAndRing()
|
|
|
if (!stateMachine.canHandleEvent(MatchEvent.REJECT_REQUEST)) {
|
|
|
Log.w(
|
|
|
@@ -315,19 +351,21 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
is Rlt.Success -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "reject success")
|
|
|
stateMachine.handleEvent(MatchEvent.REJECT_REQUEST)
|
|
|
- clearData()
|
|
|
+ clearData(REJECT_SUCCESS)
|
|
|
}
|
|
|
|
|
|
is Rlt.Failed -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "reject failed, ${rlt.error}")
|
|
|
stateMachine.handleEvent(MatchEvent.MATCH_TIMEOUT)
|
|
|
- clearData()
|
|
|
+ clearData(REJECT_FAIL)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
override fun timeout() {
|
|
|
+ matchNotifyFloatView?.cancelNotifyView()
|
|
|
+ matchNotifyFloatView = null
|
|
|
stopVibrateAndRing()
|
|
|
if (!stateMachine.canHandleEvent(MatchEvent.MATCH_TIMEOUT)) {
|
|
|
Log.i(
|
|
|
@@ -348,13 +386,13 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
is Rlt.Success -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "timeout success")
|
|
|
stateMachine.handleEvent(MatchEvent.MATCH_TIMEOUT)
|
|
|
- clearData()
|
|
|
+ clearData(TIMEOUT_SUCCESS)
|
|
|
}
|
|
|
|
|
|
is Rlt.Failed -> {
|
|
|
Log.i(TAG_CALL_MATCH_MODE, "timeout failed, ${rlt.error}")
|
|
|
stateMachine.handleEvent(MatchEvent.MATCH_TIMEOUT)
|
|
|
- clearData()
|
|
|
+ clearData(TIMEOUT_FAIL)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -372,12 +410,16 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
return matchId != 0L
|
|
|
}
|
|
|
|
|
|
- override fun clearData() {
|
|
|
+ override fun clearData(from: Int) {
|
|
|
matchId = 0L
|
|
|
roomId = 0L
|
|
|
callMode = CallType.Voice.type
|
|
|
stateMachine.handleEvent(MatchEvent.RESET)
|
|
|
- Log.i(TAG_CALL_MATCH_MODE, "state reset")
|
|
|
+ Log.i(TAG_CALL_MATCH_MODE, "state reset $from")
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun removeCallTimeout() {
|
|
|
+ mainHandler.removeCallbacks(callTimeout)
|
|
|
}
|
|
|
|
|
|
private fun stopVibrateAndRing() {
|
|
|
@@ -423,7 +465,7 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
start()
|
|
|
}
|
|
|
} catch (e: Exception) {
|
|
|
- Log.e(TAG_CALL_MATCH_MODE, "match mode start ring fail", e)
|
|
|
+ Log.e(TAG_CALL_MATCH_MODE, "match mode start ring fail $e")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -437,7 +479,29 @@ class MatchManager : BaseFrame<IMatchListener>(), IMatchManager {
|
|
|
}
|
|
|
mediaPlayer = null
|
|
|
} catch (e: Exception) {
|
|
|
- Log.e(TAG_CALL_MATCH_MODE, "match mode stop ring fail", e)
|
|
|
+ Log.e(TAG_CALL_MATCH_MODE, "match mode stop ring fail $e")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private fun handleInBackground(data: CallMatchReqAsk) {
|
|
|
+ val hasFloatPermission = PermissionRequester.newInstance(PermissionRequester.FLOAT_PERMISSION).has()
|
|
|
+ val hasNotificationPermission = PermissionRequest.isNotificationEnabled()
|
|
|
+ launch(Dispatcher.UI) {
|
|
|
+ if(hasFloatPermission) {
|
|
|
+ matchNotifyFloatView = MatchFloatWindowView(MatchFloatWindowData(MODE_SYSTEM)).apply {
|
|
|
+ showNotifyView(
|
|
|
+ data.userInfo, data.matchTimeout, data.matchId
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else if(hasNotificationPermission) {
|
|
|
+ matchNotifyFloatView = MatchNotificationView(AppUtil.appContext).apply {
|
|
|
+ showNotifyView(
|
|
|
+ data.userInfo, data.matchTimeout, data.matchId
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Log.d(TAG_CALL_MATCH_MODE, "App is in background with no permission")
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|