diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 6675e94ad9..2fe5162fa7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -141,10 +141,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO return (ApplicationContext) context.getApplicationContext(); } - public CallComponent getCallComponent() { - return EntryPoints.get(getApplicationContext(), CallComponent.class); - } - public DatabaseComponent getDatabaseComponent() { return EntryPoints.get(getApplicationContext(), DatabaseComponent.class); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt index c18ece51ea..05ca908e5f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt @@ -43,10 +43,6 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() { const val ACTION_ANSWER = "answer" const val ACTION_END = "end-call" - const val EXTRA_SDP = "WebRtcTestsActivity_EXTRA_SDP" - const val EXTRA_ADDRESS = "WebRtcTestsActivity_EXTRA_ADDRESS" - const val EXTRA_CALL_ID = "WebRtcTestsActivity_EXTRA_CALL_ID" - const val BUSY_SIGNAL_DELAY_FINISH = 5500L } @@ -59,13 +55,9 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() { private lateinit var callAddress: Address private lateinit var callId: UUID - override fun onBackPressed() { - endCall() - } - override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { - endCall() + finish() return true } return super.onOptionsItemSelected(item) @@ -94,227 +86,19 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() { } } - local_renderer.run { - setEnableHardwareScaler(true) - init(eglBase.eglBaseContext, null) - } - - remote_renderer.run { - setEnableHardwareScaler(true) - init(eglBase.eglBaseContext, null) - } - - end_call_button.setOnClickListener { - endCall() - } - - switch_camera_button.setOnClickListener { - videoCapturer?.switchCamera(null) - } - - switch_audio_button.setOnClickListener { - - } - - // create either call or answer - callId = intent.getStringExtra(EXTRA_CALL_ID).let(UUID::fromString) - if (intent.action == ACTION_ANSWER) { - callAddress = intent.getParcelableExtra(EXTRA_ADDRESS) ?: run { finish(); return } - val offerSdp = intent.getStringArrayExtra(EXTRA_SDP)!![0] - peerConnection.setRemoteDescription(this, SessionDescription(SessionDescription.Type.OFFER, offerSdp)) - peerConnection.createAnswer(this, MediaConstraints()) - } else { - callAddress = intent.getParcelableExtra(EXTRA_ADDRESS) ?: run { finish(); return } - peerConnection.createOffer(this, MediaConstraints()) - } - - lifecycleScope.launchWhenCreated { - while (this.isActive) { - val answer = synchronized(WebRtcUtils.callCache) { - WebRtcUtils.callCache[callId]?.firstOrNull { it.type == SignalServiceProtos.CallMessage.Type.ANSWER } - } - if (answer != null) { - peerConnection.setRemoteDescription( - this@WebRtcCallActivity, - SessionDescription(SessionDescription.Type.ANSWER, answer.sdps[0]) - ) - break - } - delay(2_000L) - } - } - registerReceiver(object: BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - endCall() + finish() } }, IntentFilter(ACTION_END)) - - lifecycleScope.launchWhenResumed { - while (this.isActive) { - delay(2_000L) - peerConnection.getStats(this@WebRtcCallActivity) - synchronized(WebRtcUtils.callCache) { - val set = WebRtcUtils.callCache[callId] ?: mutableSetOf() - set.filter { it.hashCode() !in acceptedCallMessageHashes - && it.type == SignalServiceProtos.CallMessage.Type.ICE_CANDIDATES }.forEach { callMessage -> - callMessage.iceCandidates().forEach { candidate -> - peerConnection.addIceCandidate(candidate) - } - acceptedCallMessageHashes.add(callMessage.hashCode()) - } - } - } - } } private fun initializeResources() { } - private fun endCall() { - if (isFinishing) return - val uuid = callId - - MessageSender.sendNonDurably( - CallMessage.endCall(uuid), - callAddress - ) - peerConnection.close() - finish() - } - - override fun onDestroy() { - super.onDestroy() - endCall() - } - private fun setupStreams() { - val videoSource = connectionFactory.createVideoSource(false) - videoCapturer?.initialize(surfaceHelper, local_renderer.context, videoSource.capturerObserver) ?: run { - finish() - return - } - videoCapturer?.startCapture(HD_VIDEO_WIDTH, HD_VIDEO_HEIGHT, 10) - - val audioTrack = connectionFactory.createAudioTrack(LOCAL_TRACK_ID + "_audio", audioSource) - val videoTrack = connectionFactory.createVideoTrack(LOCAL_TRACK_ID, videoSource) - videoTrack.addSink(local_renderer) - - val stream = connectionFactory.createLocalMediaStream(LOCAL_STREAM_ID) - stream.addTrack(videoTrack) - stream.addTrack(audioTrack) - - peerConnection.addStream(stream) - } - - override fun onSignalingChange(p0: PeerConnection.SignalingState?) { - Log.d("Loki-RTC", "onSignalingChange: $p0") - } - - override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) { - Log.d("Loki-RTC", "onIceConnectionChange: $p0") - } - - override fun onIceConnectionReceivingChange(p0: Boolean) { - Log.d("Loki-RTC", "onIceConnectionReceivingChange: $p0") - } - - override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) { - Log.d("Loki-RTC", "onIceGatheringChange: $p0") - } - - override fun onIceCandidate(iceCandidate: IceCandidate?) { - Log.d("Loki-RTC", "onIceCandidate: $iceCandidate") - if (iceCandidate == null) return - // TODO: in a lokinet world, these might have to be filtered specifically to drop anything that is not .loki - peerConnection.addIceCandidate(iceCandidate) - candidates.add(iceCandidate) - iceDebouncer.publish { - MessageSender.sendNonDurably( - CallMessage(SignalServiceProtos.CallMessage.Type.ICE_CANDIDATES, - candidates.map { it.sdp }, - candidates.map { it.sdpMLineIndex }, - candidates.map { it.sdpMid }, - callId - ), - callAddress - ) - } - } - - override fun onIceCandidatesRemoved(p0: Array?) { - Log.d("Loki-RTC", "onIceCandidatesRemoved: $p0") - peerConnection.removeIceCandidates(p0) - } - - override fun onAddStream(remoteStream: MediaStream?) { - Log.d("Loki-RTC", "onAddStream: $remoteStream") - if (remoteStream == null) { - return - } - - remoteStream.videoTracks.firstOrNull()?.addSink(remote_renderer) - } - - override fun onRemoveStream(p0: MediaStream?) { - Log.d("Loki-RTC", "onRemoveStream: $p0") - } - - override fun onDataChannel(p0: DataChannel?) { - Log.d("Loki-RTC", "onDataChannel: $p0") - } - - override fun onRenegotiationNeeded() { - Log.d("Loki-RTC", "onRenegotiationNeeded") - } - - override fun onAddTrack(p0: RtpReceiver?, p1: Array?) { - Log.d("Loki-RTC", "onAddTrack: $p0: $p1") - } - - override fun onCreateSuccess(sdp: SessionDescription) { - Log.d("Loki-RTC", "onCreateSuccess: ${sdp.type}") - when (sdp.type) { - SessionDescription.Type.OFFER -> { - peerConnection.setLocalDescription(this, sdp) - MessageSender.sendNonDurably( - CallMessage(SignalServiceProtos.CallMessage.Type.OFFER, - listOf(sdp.description), - listOf(), - listOf(), - callId - ), - callAddress - ) - } - SessionDescription.Type.ANSWER -> { - peerConnection.setLocalDescription(this, sdp) - MessageSender.sendNonDurably( - CallMessage(SignalServiceProtos.CallMessage.Type.ANSWER, - listOf(sdp.description), - listOf(), - listOf(), - callId - ), - callAddress - ) - } - null, SessionDescription.Type.PRANSWER -> TODO("do the PR answer create success handling") // MessageSender.send() - } - } - - override fun onSetSuccess() { - Log.d("Loki-RTC", "onSetSuccess") - } - - override fun onCreateFailure(p0: String?) { - Log.d("Loki-RTC", "onCreateFailure: $p0") - } - - override fun onSetFailure(p0: String?) { - Log.d("Loki-RTC", "onSetFailure: $p0") } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 014def0457..047842e08a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -187,17 +187,10 @@ object ConversationMenuHelper { .setTitle("Call") .setMessage("Use relay?") .setPositiveButton("Use Relay") { d, w -> - val intent = Intent(context, WebRtcCallActivity::class.java) - intent.putExtra(WebRtcCallActivity.EXTRA_CALL_ID, UUID.randomUUID().toString()) - intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address) - val activity = context as AppCompatActivity - activity.startActivity(intent) + TODO() } .setNeutralButton("P2P only") { d, w -> - val intent = Intent(context, WebRtcCallActivity::class.java) - intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address) - val activity = context as AppCompatActivity - activity.startActivity(intent) + TODO() } .show() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/CallModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/CallModule.kt index bf0cd73bb0..1f2a1228e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/CallModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/CallModule.kt @@ -5,19 +5,19 @@ import dagger.Binds import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.components.ServiceComponent import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.android.scopes.ServiceScoped import dagger.hilt.components.SingletonComponent import org.session.libsession.database.CallDataProvider import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.webrtc.CallManager import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat -import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager -import org.thoughtcrime.securesms.webrtc.data.SessionCallDataProvider import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class CallModule { +object CallModule { @Provides @Singleton @@ -25,11 +25,7 @@ abstract class CallModule { @Provides @Singleton - fun provideCallManager(@ApplicationContext context: Context, storage: Storage, audioManagerCompat: AudioManagerCompat) = + fun provideCallManager(@ApplicationContext context: Context, audioManagerCompat: AudioManagerCompat) = CallManager(context, audioManagerCompat) - @Binds - @Singleton - abstract fun bindCallDataProvider(sessionCallDataProvider: SessionCallDataProvider): CallDataProvider - } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt index d92c1bf752..0a1171e504 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt @@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider import org.thoughtcrime.securesms.database.* import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper -import org.thoughtcrime.securesms.webrtc.data.SessionCallDataProvider import javax.inject.Singleton @Module diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt index a6ab506f79..76a24a0277 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt @@ -28,7 +28,8 @@ import org.thoughtcrime.securesms.webrtc.* import org.thoughtcrime.securesms.webrtc.CallManager.CallState.* import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger import org.thoughtcrime.securesms.webrtc.locks.LockManager -import org.webrtc.SessionDescription +import org.webrtc.* +import org.webrtc.PeerConnection.IceConnectionState.* import java.lang.AssertionError import java.util.* import java.util.concurrent.ExecutionException @@ -37,7 +38,7 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject @AndroidEntryPoint -class WebRtcCallService: Service() { +class WebRtcCallService: Service(), PeerConnection.Observer { @Inject lateinit var callManager: CallManager @@ -62,7 +63,6 @@ class WebRtcCallService: Service() { const val ACTION_RESPONSE_MESSAGE = "RESPONSE_MESSAGE" const val ACTION_ICE_MESSAGE = "ICE_MESSAGE" - const val ACTION_ICE_CANDIDATE = "ICE_CANDIDATE" const val ACTION_CALL_CONNECTED = "CALL_CONNECTED" const val ACTION_REMOTE_HANGUP = "REMOTE_HANGUP" const val ACTION_REMOTE_BUSY = "REMOTE_BUSY" @@ -118,6 +118,7 @@ class WebRtcCallService: Service() { private var callReceiver: IncomingPstnCallReceiver? = null private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null + private var uncaughtExceptionHandlerManager: UncaughtExceptionHandlerManager? = null @Synchronized private fun terminate() { @@ -155,7 +156,7 @@ class WebRtcCallService: Service() { action == ACTION_REMOTE_VIDEO_MUTE -> handleRemoteVideoMute(intent) action == ACTION_RESPONSE_MESSAGE -> handleResponseMessage(intent) action == ACTION_ICE_MESSAGE -> handleRemoteIceCandidate(intent) - action == ACTION_ICE_CANDIDATE -> handleLocalIceCandidate(intent) + action == ACTION_ICE_CONNECTED -> handleIceConnected(intent) action == ACTION_CALL_CONNECTED -> handleCallConnected(intent) action == ACTION_CHECK_TIMEOUT -> handleCheckTimeout(intent) action == ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent) @@ -166,15 +167,18 @@ class WebRtcCallService: Service() { override fun onCreate() { super.onCreate() - // create audio manager + callManager.registerListener(this) registerIncomingPstnCallReceiver() registerWiredHeadsetStateReceiver() getSystemService(TelephonyManager::class.java) .listen(hangupOnCallAnswered, PhoneStateListener.LISTEN_CALL_STATE) - // reset call notification - // register uncaught exception handler - // register network receiver - // telephony listen to call state + registerUncaughtExceptionHandler() + } + + private fun registerUncaughtExceptionHandler() { + uncaughtExceptionHandlerManager = UncaughtExceptionHandlerManager().apply { + registerHandler(ProximityLockRelease(lockManager)) + } } private fun registerIncomingPstnCallReceiver() { @@ -215,7 +219,7 @@ class WebRtcCallService: Service() { private fun handleBusyMessage(intent: Intent) { val recipient = getRemoteRecipient(intent) val callId = getCallId(intent) - if (callManager.currentConnectionState != STATE_DIALING || callManager.callId != callManager.callId || callManager.recipient != callManager.recipient) { + if (callManager.currentConnectionState != STATE_DIALING || callManager.callId != callId || callManager.recipient != recipient) { Log.w(TAG,"Got busy message for inactive session...") return } @@ -412,10 +416,25 @@ class WebRtcCallService: Service() { } private fun handleRemoteIceCandidate(intent: Intent) { - + val callId = getCallId(intent) + val sdpMids = intent.getStringArrayExtra(EXTRA_ICE_SDP_MID) ?: return + val sdpLineIndexes = intent.getIntArrayExtra(EXTRA_ICE_SDP_LINE_INDEX) ?: return + val sdps = intent.getStringArrayExtra(EXTRA_ICE_SDP) ?: return + if (sdpMids.size != sdpLineIndexes.size || sdpLineIndexes.size != sdps.size) { + Log.w(TAG,"sdp info not of equal length") + return + } + val iceCandidates = (0 until sdpMids.size).map { index -> + IceCandidate( + sdpMids[index], + sdpLineIndexes[index], + sdps[index] + ) + } + callManager.handleRemoteIceCandidate(iceCandidates, callId) } - private fun handleLocalIceCandidate(intent: Intent) { + private fun handleIceConnected(intent: Intent) { } @@ -469,12 +488,14 @@ class WebRtcCallService: Service() { System.currentTimeMillis() - intent.getLongExtra(EXTRA_TIMESTAMP, -1) > TimeUnit.MINUTES.toMillis(2) override fun onDestroy() { - super.onDestroy() + callManager.unregisterListener(this) callReceiver?.let { receiver -> unregisterReceiver(receiver) } callReceiver = null - // unregister exception handler + uncaughtExceptionHandlerManager?.unregister() + callManager.onDestroy() + super.onDestroy() // shutdown audiomanager // unregister network receiver // unregister power button @@ -553,4 +574,37 @@ class WebRtcCallService: Service() { return expectedState == currentState && expectedCallId == currentCallId } + override fun onSignalingChange(p0: PeerConnection.SignalingState?) {} + + override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState?) { + if (newState in arrayOf(CONNECTED, COMPLETED)) { + val intent = Intent(this, WebRtcCallService::class.java) + .setAction(ACTION_ICE_CONNECTED) + startService(intent) + } else if (newState == FAILED) { + val intent = Intent(this, WebRtcCallService::class.java) + .setAction(ACTION_REMOTE_HANGUP) + .putExtra(EXTRA_CALL_ID, callManager.callId) + + startService(intent) + } + } + + override fun onIceConnectionReceivingChange(p0: Boolean) {} + + override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {} + + override fun onIceCandidate(p0: IceCandidate?) {} + + override fun onIceCandidatesRemoved(p0: Array?) {} + + override fun onAddStream(p0: MediaStream?) {} + + override fun onRemoveStream(p0: MediaStream?) {} + + override fun onDataChannel(p0: DataChannel?) {} + + override fun onRenegotiationNeeded() {} + + override fun onAddTrack(p0: RtpReceiver?, p1: Array?) {} } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/AudioManagerCommand.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/AudioManagerCommand.kt index fe6021ed9b..182b21c4ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/AudioManagerCommand.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/AudioManagerCommand.kt @@ -10,6 +10,12 @@ open class AudioManagerCommand: Parcelable { @Parcelize object Initialize: AudioManagerCommand() + @Parcelize + object Shutdown: AudioManagerCommand() + + @Parcelize + object UpdateAudioDeviceState: AudioManagerCommand() + @Parcelize data class StartOutgoingRinger(val type: OutgoingRinger.Type): AudioManagerCommand() diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt index e49dad9bce..03952556c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.webrtc import android.content.Context -import android.content.Intent import android.telephony.TelephonyManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow @@ -64,6 +63,16 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne private val signalAudioManager: SignalAudioManager = SignalAudioManager(context, this, audioManager) + private val peerConnectionObservers = mutableSetOf() + + fun registerListener(listener: PeerConnection.Observer) { + peerConnectionObservers.add(listener) + } + + fun unregisterListener(listener: PeerConnection.Observer) { + peerConnectionObservers.remove(listener) + } + private val _audioEvents = MutableStateFlow(StateEvent.AudioEnabled(false)) val audioEvents = _audioEvents.asSharedFlow() private val _videoEvents = MutableStateFlow(StateEvent.VideoEnabled(false)) @@ -183,47 +192,47 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne } override fun onSignalingChange(newState: PeerConnection.SignalingState) { - + peerConnectionObservers.forEach { listener -> listener.onSignalingChange(newState) } } override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState) { - + peerConnectionObservers.forEach { listener -> listener.onIceConnectionChange(newState) } } override fun onIceConnectionReceivingChange(receiving: Boolean) { - + peerConnectionObservers.forEach { listener -> listener.onIceConnectionReceivingChange(receiving) } } override fun onIceGatheringChange(newState: PeerConnection.IceGatheringState) { - + peerConnectionObservers.forEach { listener -> listener.onIceGatheringChange(newState) } } - override fun onIceCandidate(p0: IceCandidate?) { - + override fun onIceCandidate(iceCandidate: IceCandidate?) { + peerConnectionObservers.forEach { listener -> listener.onIceCandidate(iceCandidate) } } - override fun onIceCandidatesRemoved(p0: Array?) { - + override fun onIceCandidatesRemoved(candidates: Array?) { + peerConnectionObservers.forEach { listener -> listener.onIceCandidatesRemoved(candidates) } } override fun onAddStream(p0: MediaStream?) { - + peerConnectionObservers.forEach { listener -> listener.onAddStream(p0) } } override fun onRemoveStream(p0: MediaStream?) { - + peerConnectionObservers.forEach { listener -> listener.onRemoveStream(p0) } } override fun onDataChannel(p0: DataChannel?) { - + peerConnectionObservers.forEach { listener -> listener.onDataChannel(p0) } } override fun onRenegotiationNeeded() { - + peerConnectionObservers.forEach { listener -> listener.onRenegotiationNeeded() } } override fun onAddTrack(p0: RtpReceiver?, p1: Array?) { - + peerConnectionObservers.forEach { listener -> listener.onAddTrack(p0, p1) } } override fun onBufferedAmountChange(l: Long) { @@ -476,4 +485,8 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne } } + fun onDestroy() { + signalAudioManager.handleCommand(AudioManagerCommand.Shutdown) + } + } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/UncaughtExceptionHandlerManager.java b/app/src/main/java/org/thoughtcrime/securesms/webrtc/UncaughtExceptionHandlerManager.java new file mode 100644 index 0000000000..56271b9803 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/UncaughtExceptionHandlerManager.java @@ -0,0 +1,42 @@ +package org.thoughtcrime.securesms.webrtc; + +import org.session.libsignal.utilities.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Allows multiple default uncaught exception handlers to be registered + * + * Calls all registered handlers in reverse order of registration. + * Errors in one handler do not prevent subsequent handlers from being called. + */ +public class UncaughtExceptionHandlerManager implements Thread.UncaughtExceptionHandler { + private final Thread.UncaughtExceptionHandler originalHandler; + private final List handlers = new ArrayList(); + + public UncaughtExceptionHandlerManager() { + originalHandler = Thread.getDefaultUncaughtExceptionHandler(); + registerHandler(originalHandler); + Thread.setDefaultUncaughtExceptionHandler(this); + } + + public void registerHandler(Thread.UncaughtExceptionHandler handler) { + handlers.add(handler); + } + + public void unregister() { + Thread.setDefaultUncaughtExceptionHandler(originalHandler); + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + for (int i = handlers.size() - 1; i >= 0; i--) { + try { + handlers.get(i).uncaughtException(thread, throwable); + } catch(Throwable t) { + Log.e("UncaughtExceptionHandlerManager", "Error in uncaught exception handling", t); + } + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallServiceReceivers.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallServiceReceivers.kt index 694d343ed6..0c1ba5bcda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallServiceReceivers.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallServiceReceivers.kt @@ -8,6 +8,7 @@ import android.telephony.TelephonyManager import dagger.hilt.android.AndroidEntryPoint import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.service.WebRtcCallService +import org.thoughtcrime.securesms.webrtc.locks.LockManager import javax.inject.Inject @@ -26,11 +27,11 @@ class HangUpRtcOnPstnCallAnsweredListener(private val hangupListener: ()->Unit): } } -@AndroidEntryPoint +//@AndroidEntryPoint class NetworkReceiver: BroadcastReceiver() { - @Inject - lateinit var callManager: CallManager +// @Inject +// lateinit var callManager: CallManager override fun onReceive(context: Context, intent: Intent) { TODO("Not yet implemented") @@ -47,13 +48,13 @@ class PowerButtonReceiver : BroadcastReceiver() { } } -class ProximityLockRelease: Thread.UncaughtExceptionHandler { +class ProximityLockRelease(private val lockManager: LockManager): Thread.UncaughtExceptionHandler { companion object { private val TAG = Log.tag(ProximityLockRelease::class.java) } override fun uncaughtException(t: Thread, e: Throwable) { Log.e(TAG,"Uncaught exception - releasing proximity lock", e) - // lockManager update phone state + lockManager.updatePhoneState(LockManager.PhoneState.IDLE) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt index 342725c552..d2172e9753 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt @@ -37,7 +37,7 @@ class SignalAudioManager(private val context: Context, private val androidAudioManager: AudioManagerCompat) { private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio").apply { start() } - private val handler = SignalAudioHandler(commandAndControlThread!!.looper) + private var handler = SignalAudioHandler(commandAndControlThread!!.looper) private val signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler) @@ -69,6 +69,8 @@ class SignalAudioManager(private val context: Context, handler.post { when (command) { is AudioManagerCommand.Initialize -> initialize() + is AudioManagerCommand.Shutdown -> shutdown() + is AudioManagerCommand.UpdateAudioDeviceState -> updateAudioDeviceState() is AudioManagerCommand.Start -> start() is AudioManagerCommand.Stop -> stop(command.playDisconnect) is AudioManagerCommand.SetDefaultDevice -> setDefaultAudioDevice(command.device, command.clearUserEarpieceSelection) @@ -84,6 +86,9 @@ class SignalAudioManager(private val context: Context, Log.i(TAG, "Initializing audio manager state: $state") if (state == State.UNINITIALIZED) { + commandAndControlThread = HandlerThread("call-audio").apply { start() } + handler = SignalAudioHandler(commandAndControlThread!!.looper) + savedAudioMode = androidAudioManager.mode savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalBluetoothManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalBluetoothManager.kt index e7f93f5f8d..f7177547ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalBluetoothManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalBluetoothManager.kt @@ -9,6 +9,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.webrtc.AudioManagerCommand import java.util.concurrent.TimeUnit /** @@ -181,7 +182,7 @@ class SignalBluetoothManager( } private fun updateAudioDeviceState() { - audioManager.updateAudioDeviceState() + audioManager.handleCommand(AudioManagerCommand.UpdateAudioDeviceState) } private fun startTimer() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/data/SessionCallDataProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/data/SessionCallDataProvider.kt deleted file mode 100644 index 27dddb28b0..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/data/SessionCallDataProvider.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.thoughtcrime.securesms.webrtc.data - -import org.session.libsession.database.CallDataProvider -import org.session.libsession.database.StorageProtocol -import org.thoughtcrime.securesms.webrtc.CallManager -import javax.inject.Inject - -class SessionCallDataProvider @Inject constructor(private val storage: StorageProtocol, - private val callManager: CallManager): CallDataProvider { - -} \ No newline at end of file