session-android/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt

236 lines
9 KiB
Kotlin
Raw Normal View History

package org.thoughtcrime.securesms.calls
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
2021-08-30 08:39:47 +02:00
import android.content.Intent
import android.content.IntentFilter
import android.graphics.BlendMode
import android.graphics.PorterDuff
2021-11-12 07:07:39 +01:00
import android.graphics.drawable.ColorDrawable
import android.media.AudioManager
import android.os.Bundle
import android.view.MenuItem
2021-11-12 07:07:39 +01:00
import android.view.View
import android.view.WindowManager
import androidx.activity.viewModels
2021-11-12 07:07:39 +01:00
import androidx.core.content.ContextCompat
2021-11-10 01:57:03 +01:00
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.load.engine.DiskCacheStrategy
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_webrtc.*
2021-11-10 01:57:03 +01:00
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.avatars.ProfileContactPhoto
import org.session.libsession.messaging.contacts.Contact
2021-08-30 08:39:47 +02:00
import org.session.libsession.utilities.Address
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.service.WebRtcCallService
import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import org.thoughtcrime.securesms.webrtc.CallViewModel
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.*
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.*
import org.webrtc.IceCandidate
2021-10-21 23:52:57 +02:00
import java.util.*
2021-08-20 01:14:54 +02:00
@AndroidEntryPoint
class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
2021-08-20 01:14:54 +02:00
companion object {
2021-08-30 08:39:47 +02:00
const val ACTION_ANSWER = "answer"
const val ACTION_END = "end-call"
2021-08-30 08:39:47 +02:00
const val BUSY_SIGNAL_DELAY_FINISH = 5500L
2021-08-20 01:14:54 +02:00
}
private val viewModel by viewModels<CallViewModel>()
private val glide by lazy { GlideApp.with(this) }
2021-11-10 01:57:03 +01:00
private var uiJob: Job? = null
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return super.onOptionsItemSelected(item)
}
2021-11-12 07:07:39 +01:00
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent?.action == ACTION_ANSWER) {
val answerIntent = WebRtcCallService.acceptCallIntent(this)
ContextCompat.startForegroundService(this,answerIntent)
}
}
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready)
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContentView(R.layout.activity_webrtc)
volumeControlStream = AudioManager.STREAM_VOICE_CALL
initializeResources()
Permissions.with(this)
.request(Manifest.permission.RECORD_AUDIO)
.onAllGranted {
setupStreams()
}
.execute()
if (intent.action == ACTION_ANSWER) {
val answerIntent = WebRtcCallService.acceptCallIntent(this)
2021-11-12 07:07:39 +01:00
ContextCompat.startForegroundService(this,answerIntent)
}
speakerPhoneButton.setOnClickListener {
val command = AudioManagerCommand.SetUserDevice( if (viewModel.isSpeaker) EARPIECE else SPEAKER_PHONE)
WebRtcCallService.sendAudioManagerCommand(this, command)
}
2021-11-12 07:07:39 +01:00
acceptCallButton.setOnClickListener {
val answerIntent = WebRtcCallService.acceptCallIntent(this)
ContextCompat.startForegroundService(this,answerIntent)
}
declineCallButton.setOnClickListener {
val declineIntent = WebRtcCallService.hangupIntent(this)
startService(declineIntent)
}
registerReceiver(object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
finish()
}
},IntentFilter(ACTION_END))
2021-11-10 01:57:03 +01:00
enableCameraButton.setOnClickListener {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.onAllGranted {
val intent = WebRtcCallService.cameraEnabled(this, !viewModel.videoEnabled)
startService(intent)
}
.execute()
2021-11-10 01:57:03 +01:00
}
switchCameraButton.setOnClickListener {
startService(WebRtcCallService.flipCamera(this))
}
endCallButton.setOnClickListener {
startService(WebRtcCallService.hangupIntent(this))
}
}
private fun initializeResources() {
}
private fun setupStreams() {
}
2021-11-10 01:57:03 +01:00
override fun onStart() {
super.onStart()
uiJob = lifecycleScope.launch {
launch {
viewModel.audioDeviceState.collect { state ->
val speakerEnabled = state.selectedDevice == SPEAKER_PHONE
speakerPhoneButton.setImageResource(
if (speakerEnabled) R.drawable.ic_baseline_volume_up_24
else R.drawable.ic_baseline_volume_mute_24
)
}
}
launch {
viewModel.callState.collect { state ->
2021-11-12 07:07:39 +01:00
when (state) {
CALL_RINGING -> {
}
CALL_OUTGOING -> {
}
CALL_CONNECTED -> {
}
}
controlGroup.isVisible = state in listOf(CALL_CONNECTED, CALL_OUTGOING, CALL_INCOMING)
remote_loading_view.isVisible = state !in listOf(CALL_CONNECTED, CALL_RINGING)
incomingControlGroup.isVisible = state == CALL_RINGING
2021-11-10 01:57:03 +01:00
}
}
launch {
viewModel.recipient.collect { latestRecipient ->
if (latestRecipient.recipient != null) {
val signalProfilePicture = latestRecipient.recipient.contactPhoto
val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject
if (signalProfilePicture != null && avatar != "0" && avatar != "") {
glide.clear(remote_recipient)
glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC).circleCrop().into(remote_recipient)
} else {
val publicKey = latestRecipient.recipient.address.serialize()
val displayName = getUserDisplayName(publicKey)
val sizeInPX = resources.getDimensionPixelSize(R.dimen.extra_large_profile_picture_size)
glide.clear(remote_recipient)
glide.load(AvatarPlaceholderGenerator.generate(this@WebRtcCallActivity, sizeInPX, publicKey, displayName))
.diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(remote_recipient)
}
} else {
glide.clear(remote_recipient)
}
}
}
2021-11-10 01:57:03 +01:00
launch {
viewModel.localVideoEnabledState.collect { isEnabled ->
local_renderer.removeAllViews()
if (isEnabled) {
viewModel.localRenderer?.let { surfaceView ->
surfaceView.setZOrderOnTop(true)
local_renderer.addView(surfaceView)
}
}
local_renderer.isVisible = isEnabled
enableCameraButton.setImageResource(
if (isEnabled) R.drawable.ic_baseline_videocam_off_24
else R.drawable.ic_baseline_videocam_24
)
}
}
launch {
viewModel.remoteVideoEnabledState.collect { isEnabled ->
remote_renderer.removeAllViews()
if (isEnabled) {
viewModel.remoteRenderer?.let { remote_renderer.addView(it) }
}
remote_renderer.isVisible = isEnabled
remote_recipient.isVisible = !isEnabled
}
2021-11-10 01:57:03 +01:00
}
}
}
2021-11-12 07:07:39 +01:00
private fun getUserDisplayName(publicKey: String): String {
val contact = DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey)
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
}
2021-11-10 01:57:03 +01:00
override fun onStop() {
super.onStop()
uiJob?.cancel()
}
}