refactor: compile errors and refactoring to view binding

This commit is contained in:
jubb 2022-02-08 12:04:55 +11:00
parent 38164ea23d
commit 53127b69de
12 changed files with 148 additions and 181 deletions

View File

@ -17,6 +17,7 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'witness' apply plugin: 'witness'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: 'kotlinx-serialization' apply plugin: 'kotlinx-serialization'
apply plugin: 'dagger.hilt.android.plugin' apply plugin: 'dagger.hilt.android.plugin'
@ -157,7 +158,7 @@ dependencies {
testImplementation 'org.robolectric:shadows-multidex:4.4' testImplementation 'org.robolectric:shadows-multidex:4.4'
} }
def canonicalVersionCode = 249 def canonicalVersionCode = 250
def canonicalVersionName = "1.12.2" def canonicalVersionName = "1.12.2"
def postFixSize = 10 def postFixSize = 10

View File

@ -134,6 +134,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject Storage storage; @Inject Storage storage;
@Inject MessageDataProvider messageDataProvider; @Inject MessageDataProvider messageDataProvider;
@Inject JobDatabase jobDatabase; @Inject JobDatabase jobDatabase;
@Inject TextSecurePreferences textSecurePreferences;
CallMessageProcessor callMessageProcessor; CallMessageProcessor callMessageProcessor;
private volatile boolean isAppVisible; private volatile boolean isAppVisible;
@ -161,7 +162,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
public void onCreate() { public void onCreate() {
DatabaseModule.init(this); DatabaseModule.init(this);
super.onCreate(); super.onCreate();
callMessageProcessor = new CallMessageProcessor(this, ProcessLifecycleOwner.get().getLifecycle(), storage); callMessageProcessor = new CallMessageProcessor(this, textSecurePreferences, ProcessLifecycleOwner.get().getLifecycle(), storage);
Log.i(TAG, "onCreate()"); Log.i(TAG, "onCreate()");
startKovenant(); startKovenant();
initializeSecurityProvider(); initializeSecurityProvider();

View File

@ -9,20 +9,19 @@ import android.media.AudioManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import android.widget.FrameLayout
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.contains
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_conversation_v2.* import kotlinx.coroutines.Job
import kotlinx.android.synthetic.main.activity_webrtc.* import kotlinx.coroutines.delay
import kotlinx.coroutines.* import kotlinx.coroutines.isActive
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch
import network.loki.messenger.R import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityWebrtcBinding
import org.apache.commons.lang3.time.DurationFormatUtils import org.apache.commons.lang3.time.DurationFormatUtils
import org.session.libsession.avatars.ProfileContactPhoto import org.session.libsession.avatars.ProfileContactPhoto
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
@ -36,11 +35,10 @@ import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import org.thoughtcrime.securesms.webrtc.CallViewModel import org.thoughtcrime.securesms.webrtc.CallViewModel
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.* import org.thoughtcrime.securesms.webrtc.CallViewModel.State.*
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.* import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.*
import org.webrtc.RendererCommon
import java.util.* import java.util.*
@AndroidEntryPoint @AndroidEntryPoint
class WebRtcCallActivity: PassphraseRequiredActionBarActivity() { class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
companion object { companion object {
const val ACTION_PRE_OFFER = "pre-offer" const val ACTION_PRE_OFFER = "pre-offer"
@ -55,6 +53,7 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
private val viewModel by viewModels<CallViewModel>() private val viewModel by viewModels<CallViewModel>()
private val glide by lazy { GlideApp.with(this) } private val glide by lazy { GlideApp.with(this) }
private lateinit var binding: ActivityWebrtcBinding
private var uiJob: Job? = null private var uiJob: Job? = null
private var wantsToAnswer = false private var wantsToAnswer = false
set(value) { set(value) {
@ -75,13 +74,13 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
super.onNewIntent(intent) super.onNewIntent(intent)
if (intent?.action == ACTION_ANSWER) { if (intent?.action == ACTION_ANSWER) {
val answerIntent = WebRtcCallService.acceptCallIntent(this) val answerIntent = WebRtcCallService.acceptCallIntent(this)
ContextCompat.startForegroundService(this,answerIntent) ContextCompat.startForegroundService(this, answerIntent)
} }
} }
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready) super.onCreate(savedInstanceState, ready)
setContentView(R.layout.activity_webrtc) binding = ActivityWebrtcBinding.inflate(layoutInflater)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true) setShowWhenLocked(true)
setTurnScreenOn(true) setTurnScreenOn(true)
@ -91,7 +90,8 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
volumeControlStream = AudioManager.STREAM_VOICE_CALL volumeControlStream = AudioManager.STREAM_VOICE_CALL
if (intent.action == ACTION_ANSWER) { if (intent.action == ACTION_ANSWER) {
@ -105,17 +105,19 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(false) supportActionBar?.setDisplayHomeAsUpEnabled(false)
} }
microphoneButton.setOnClickListener { binding.microphoneButton.setOnClickListener {
val audioEnabledIntent = WebRtcCallService.microphoneIntent(this, !viewModel.microphoneEnabled) val audioEnabledIntent =
WebRtcCallService.microphoneIntent(this, !viewModel.microphoneEnabled)
startService(audioEnabledIntent) startService(audioEnabledIntent)
} }
speakerPhoneButton.setOnClickListener { binding.speakerPhoneButton.setOnClickListener {
val command = AudioManagerCommand.SetUserDevice( if (viewModel.isSpeaker) EARPIECE else SPEAKER_PHONE) val command =
AudioManagerCommand.SetUserDevice(if (viewModel.isSpeaker) EARPIECE else SPEAKER_PHONE)
WebRtcCallService.sendAudioManagerCommand(this, command) WebRtcCallService.sendAudioManagerCommand(this, command)
} }
acceptCallButton.setOnClickListener { binding.acceptCallButton.setOnClickListener {
if (viewModel.currentCallState == CALL_PRE_INIT) { if (viewModel.currentCallState == CALL_PRE_INIT) {
wantsToAnswer = true wantsToAnswer = true
updateControls() updateControls()
@ -123,20 +125,21 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
answerCall() answerCall()
} }
declineCallButton.setOnClickListener { binding.declineCallButton.setOnClickListener {
val declineIntent = WebRtcCallService.denyCallIntent(this) val declineIntent = WebRtcCallService.denyCallIntent(this)
startService(declineIntent) startService(declineIntent)
} }
hangupReceiver = object: BroadcastReceiver() { hangupReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
finish() finish()
} }
} }
LocalBroadcastManager.getInstance(this).registerReceiver(hangupReceiver!!,IntentFilter(ACTION_END)) LocalBroadcastManager.getInstance(this)
.registerReceiver(hangupReceiver!!, IntentFilter(ACTION_END))
enableCameraButton.setOnClickListener { binding.enableCameraButton.setOnClickListener {
Permissions.with(this) Permissions.with(this)
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.onAllGranted { .onAllGranted {
@ -146,11 +149,11 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
.execute() .execute()
} }
switchCameraButton.setOnClickListener { binding.switchCameraButton.setOnClickListener {
startService(WebRtcCallService.flipCamera(this)) startService(WebRtcCallService.flipCamera(this))
} }
endCallButton.setOnClickListener { binding.endCallButton.setOnClickListener {
startService(WebRtcCallService.hangupIntent(this)) startService(WebRtcCallService.hangupIntent(this))
} }
@ -165,20 +168,29 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
private fun answerCall() { private fun answerCall() {
val answerIntent = WebRtcCallService.acceptCallIntent(this) val answerIntent = WebRtcCallService.acceptCallIntent(this)
ContextCompat.startForegroundService(this,answerIntent) ContextCompat.startForegroundService(this, answerIntent)
} }
private fun updateControls(state: CallViewModel.State? = null) { private fun updateControls(state: CallViewModel.State? = null) {
with (binding) {
if (state == null) { if (state == null) {
if (wantsToAnswer) { if (wantsToAnswer) {
controlGroup.isVisible = true controlGroup.isVisible = true
remote_loading_view.isVisible = true remoteLoadingView.isVisible = true
incomingControlGroup.isVisible = false incomingControlGroup.isVisible = false
} }
} else { } else {
controlGroup.isVisible = state in listOf(CALL_CONNECTED, CALL_OUTGOING, CALL_INCOMING) || (state == CALL_PRE_INIT && wantsToAnswer)
remote_loading_view.isVisible = state !in listOf(CALL_CONNECTED, CALL_RINGING, CALL_PRE_INIT) || wantsToAnswer controlGroup.isVisible = state in listOf(
incomingControlGroup.isVisible = state in listOf(CALL_RINGING, CALL_PRE_INIT) && !wantsToAnswer CALL_CONNECTED,
CALL_OUTGOING,
CALL_INCOMING
) || (state == CALL_PRE_INIT && wantsToAnswer)
remoteLoadingView.isVisible =
state !in listOf(CALL_CONNECTED, CALL_RINGING, CALL_PRE_INIT) || wantsToAnswer
incomingControlGroup.isVisible =
state in listOf(CALL_RINGING, CALL_PRE_INIT) && !wantsToAnswer
}
} }
} }
@ -191,7 +203,7 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
viewModel.audioDeviceState.collect { state -> viewModel.audioDeviceState.collect { state ->
val speakerEnabled = state.selectedDevice == SPEAKER_PHONE val speakerEnabled = state.selectedDevice == SPEAKER_PHONE
// change drawable background to enabled or not // change drawable background to enabled or not
speakerPhoneButton.isSelected = speakerEnabled binding.speakerPhoneButton.isSelected = speakerEnabled
} }
} }
@ -222,20 +234,37 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
supportActionBar?.title = displayName supportActionBar?.title = displayName
val signalProfilePicture = latestRecipient.recipient.contactPhoto val signalProfilePicture = latestRecipient.recipient.contactPhoto
val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject
val sizeInPX = resources.getDimensionPixelSize(R.dimen.extra_large_profile_picture_size) val sizeInPX =
resources.getDimensionPixelSize(R.dimen.extra_large_profile_picture_size)
if (signalProfilePicture != null && avatar != "0" && avatar != "") { if (signalProfilePicture != null && avatar != "0" && avatar != "") {
glide.clear(remote_recipient) glide.clear(binding.remoteRecipient)
glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) glide.load(signalProfilePicture)
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.circleCrop() .circleCrop()
.error(AvatarPlaceholderGenerator.generate(this@WebRtcCallActivity, sizeInPX, publicKey, displayName)) .error(
.into(remote_recipient) AvatarPlaceholderGenerator.generate(
this@WebRtcCallActivity,
sizeInPX,
publicKey,
displayName
)
)
.into(binding.remoteRecipient)
} else { } else {
glide.clear(remote_recipient) glide.clear(binding.remoteRecipient)
glide.load(AvatarPlaceholderGenerator.generate(this@WebRtcCallActivity, sizeInPX, publicKey, displayName)) glide.load(
.diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(remote_recipient) AvatarPlaceholderGenerator.generate(
this@WebRtcCallActivity,
sizeInPX,
publicKey,
displayName
)
)
.diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop()
.into(binding.remoteRecipient)
} }
} else { } else {
glide.clear(remote_recipient) glide.clear(binding.remoteRecipient)
} }
} }
} }
@ -244,10 +273,13 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
while (isActive) { while (isActive) {
val startTime = viewModel.callStartTime val startTime = viewModel.callStartTime
if (startTime == -1L) { if (startTime == -1L) {
callTime.isVisible = false binding.callTime.isVisible = false
} else { } else {
callTime.isVisible = true binding.callTime.isVisible = true
callTime.text = DurationFormatUtils.formatDuration(System.currentTimeMillis() - startTime, CALL_DURATION_FORMAT) binding.callTime.text = DurationFormatUtils.formatDuration(
System.currentTimeMillis() - startTime,
CALL_DURATION_FORMAT
)
} }
delay(1_000) delay(1_000)
@ -257,48 +289,49 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
launch { launch {
viewModel.localAudioEnabledState.collect { isEnabled -> viewModel.localAudioEnabledState.collect { isEnabled ->
// change drawable background to enabled or not // change drawable background to enabled or not
microphoneButton.isSelected = !isEnabled binding.microphoneButton.isSelected = !isEnabled
} }
} }
launch { launch {
viewModel.localVideoEnabledState.collect { isEnabled -> viewModel.localVideoEnabledState.collect { isEnabled ->
local_renderer.removeAllViews() binding.localRenderer.removeAllViews()
if (isEnabled) { if (isEnabled) {
viewModel.localRenderer?.let { surfaceView -> viewModel.localRenderer?.let { surfaceView ->
surfaceView.setZOrderOnTop(true) surfaceView.setZOrderOnTop(true)
local_renderer.addView(surfaceView) binding.localRenderer.addView(surfaceView)
} }
} }
local_renderer.isVisible = isEnabled binding.localRenderer.isVisible = isEnabled
enableCameraButton.isSelected = isEnabled binding.enableCameraButton.isSelected = isEnabled
} }
} }
launch { launch {
viewModel.remoteVideoEnabledState.collect { isEnabled -> viewModel.remoteVideoEnabledState.collect { isEnabled ->
remote_renderer.removeAllViews() binding.remoteRenderer.removeAllViews()
if (isEnabled) { if (isEnabled) {
viewModel.remoteRenderer?.let { surfaceView -> viewModel.remoteRenderer?.let { surfaceView ->
remote_renderer.addView(surfaceView) binding.remoteRenderer.addView(surfaceView)
} }
} }
remote_renderer.isVisible = isEnabled binding.remoteRenderer.isVisible = isEnabled
remote_recipient.isVisible = !isEnabled binding.remoteRecipient.isVisible = !isEnabled
} }
} }
} }
} }
private fun getUserDisplayName(publicKey: String): String { private fun getUserDisplayName(publicKey: String): String {
val contact = DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey) val contact =
DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey)
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
uiJob?.cancel() uiJob?.cancel()
remote_renderer.removeAllViews() binding.remoteRenderer.removeAllViews()
local_renderer.removeAllViews() binding.localRenderer.removeAllViews()
} }
} }

View File

@ -137,7 +137,6 @@ import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.math.sqrt import kotlin.math.sqrt
@ -168,7 +167,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
private val linkPreviewViewModel: LinkPreviewViewModel by lazy { private val linkPreviewViewModel: LinkPreviewViewModel by lazy {
ViewModelProvider(this, LinkPreviewViewModel.Factory(LinkPreviewRepository(this))) ViewModelProvider(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))
.get(LinkPreviewViewModel::class.java) .get(LinkPreviewViewModel::class.java)
} }
private val viewModel: ConversationViewModel by viewModels { private val viewModel: ConversationViewModel by viewModels {
@ -542,7 +541,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
override fun onPrepareOptionsMenu(menu: Menu): Boolean { override fun onPrepareOptionsMenu(menu: Menu): Boolean {
ConversationMenuHelper.onPrepareOptionsMenu(menu, menuInflater, viewModel.recipient, viewModel.threadId, this) { onOptionsItemSelected(it) } ConversationMenuHelper.onPrepareOptionsMenu(menu, menuInflater, viewModel.recipient, viewModel.threadId, textSecurePreferences.isCallNotificationsEnabled(), this) { onOptionsItemSelected(it) }
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
return true return true
} }

View File

@ -53,7 +53,7 @@ import java.io.IOException
object ConversationMenuHelper { object ConversationMenuHelper {
fun onPrepareOptionsMenu(menu: Menu, inflater: MenuInflater, thread: Recipient, threadId: Long, context: Context, onOptionsItemSelected: (MenuItem) -> Unit) { fun onPrepareOptionsMenu(menu: Menu, inflater: MenuInflater, thread: Recipient, threadId: Long, isCallsEnabled: Boolean, context: Context, onOptionsItemSelected: (MenuItem) -> Unit) {
// Prepare // Prepare
menu.clear() menu.clear()
val isOpenGroup = thread.isOpenGroupRecipient val isOpenGroup = thread.isOpenGroupRecipient
@ -102,7 +102,7 @@ object ConversationMenuHelper {
inflater.inflate(R.menu.menu_conversation_notification_settings, menu) inflater.inflate(R.menu.menu_conversation_notification_settings, menu)
} }
if (!thread.isGroupRecipient && TextSecurePreferences.isCallNotificationsEnabled(context)) { if (!thread.isGroupRecipient && isCallsEnabled) {
inflater.inflate(R.menu.menu_conversation_call, menu) inflater.inflate(R.menu.menu_conversation_call, menu)
} }

View File

@ -12,14 +12,11 @@ import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader import androidx.loader.content.Loader
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
@ -34,9 +31,6 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.WebRtcUtils
import org.session.libsession.utilities.Util
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.ProfilePictureModifiedEvent import org.session.libsession.utilities.ProfilePictureModifiedEvent
@ -48,7 +42,6 @@ import org.session.libsignal.utilities.toHexString
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.MuteDialog import org.thoughtcrime.securesms.MuteDialog
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
@ -76,7 +69,6 @@ import org.thoughtcrime.securesms.util.UiModeUtilities
import org.thoughtcrime.securesms.util.disableClipping import org.thoughtcrime.securesms.util.disableClipping
import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.push
import org.thoughtcrime.securesms.util.show import org.thoughtcrime.securesms.util.show
import org.thoughtcrime.securesms.webrtc.CallBottomSheet
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject

View File

@ -21,6 +21,9 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
import mobi.upod.timedurationpicker.TimeDurationPickerDialog; import mobi.upod.timedurationpicker.TimeDurationPickerDialog;
import network.loki.messenger.R; import network.loki.messenger.R;

View File

@ -1,7 +1,7 @@
package org.thoughtcrime.securesms.webrtc package org.thoughtcrime.securesms.webrtc
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager

View File

@ -1,76 +0,0 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.android.synthetic.main.fragment_call_bottom_sheet.*
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.nameTextView
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.profilePictureView
import network.loki.messenger.R
import org.session.libsession.messaging.messages.control.CallMessage
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
import org.thoughtcrime.securesms.mms.GlideApp
import java.util.*
class CallBottomSheet: BottomSheetDialogFragment() {
companion object {
const val ARGUMENT_ADDRESS = "CallBottomSheet_ADDRESS"
const val ARGUMENT_SDP = "CallBottomSheet_SDP"
const val ARGUMENT_TYPE = "CallBottomSheet_TYPE"
const val ARGUMENT_CALL_ID = "CallBottomSheet_CALL_ID"
}
private lateinit var address: Address
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_call_bottom_sheet, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
address = arguments?.getParcelable(ARGUMENT_ADDRESS) ?: return dismiss()
val sdp = arguments?.getStringArray(ARGUMENT_SDP) ?: return dismiss()
val callId = arguments?.getString(ARGUMENT_CALL_ID) ?: return dismiss()
val callUUID = UUID.fromString(callId)
val recipient = Recipient.from(requireContext(), address, false)
profilePictureView.publicKey = address.serialize()
profilePictureView.glide = GlideApp.with(this)
profilePictureView.isLarge = true
profilePictureView.update(recipient, -1)
nameTextView.text = recipient.name ?: address.serialize()
acceptButton.setOnClickListener {
// val intent = Intent(requireContext(), WebRtcCallActivity::class.java)
// val bundle = bundleOf(
// WebRtcCallActivity.EXTRA_ADDRESS to address,
// WebRtcCallActivity.EXTRA_CALL_ID to callId
// )
// intent.action = WebRtcCallActivity.ACTION_ANSWER
// bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp)
//
// intent.putExtras(bundle)
// startActivity(intent)
// dismiss()
}
declineButton.setOnClickListener {
MessageSender.sendNonDurably(CallMessage.endCall(callUUID), address)
dismiss()
}
}
}

View File

@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.util.CallNotificationBuilder
import org.webrtc.IceCandidate import org.webrtc.IceCandidate
class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle, private val storage: StorageProtocol) { class CallMessageProcessor(private val context: Context, private val textSecurePreferences: TextSecurePreferences, lifecycle: Lifecycle, private val storage: StorageProtocol) {
init { init {
lifecycle.coroutineScope.launch(IO) { lifecycle.coroutineScope.launch(IO) {
@ -31,11 +31,11 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle, p
val sender = nextMessage.sender ?: continue val sender = nextMessage.sender ?: continue
if (!storage.conversationHasOutgoing(sender) && storage.getUserPublicKey() != sender) continue if (!storage.conversationHasOutgoing(sender) && storage.getUserPublicKey() != sender) continue
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) { if (!textSecurePreferences.isCallNotificationsEnabled()) {
Log.d("Loki","Dropping call message if call notifications disabled") Log.d("Loki","Dropping call message if call notifications disabled")
if (nextMessage.type != PRE_OFFER) continue if (nextMessage.type != PRE_OFFER) continue
val sentTimestamp = nextMessage.sentTimestamp ?: continue val sentTimestamp = nextMessage.sentTimestamp ?: continue
if (TextSecurePreferences.setShownCallNotification(context)) { if (textSecurePreferences.setShownCallNotification()) {
// first time call notification encountered // first time call notification encountered
val notification = CallNotificationBuilder.getFirstCallNotification(context) val notification = CallNotificationBuilder.getFirstCallNotification(context)
context.getSystemService(NotificationManager::class.java).notify(CallNotificationBuilder.WEBRTC_NOTIFICATION, notification) context.getSystemService(NotificationManager::class.java).notify(CallNotificationBuilder.WEBRTC_NOTIFICATION, notification)

View File

@ -60,7 +60,7 @@ private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) {
private fun MessageReceiver.handleCallMessage(message: CallMessage) { private fun MessageReceiver.handleCallMessage(message: CallMessage) {
// TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing // TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing
WebRtcUtils.SIGNAL_QUEUE.offer(message) WebRtcUtils.SIGNAL_QUEUE.trySend(message)
} }
private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) { private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {

View File

@ -12,6 +12,9 @@ import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import org.session.libsession.R import org.session.libsession.R
import org.session.libsession.utilities.TextSecurePreferences.Companion.CALL_NOTIFICATIONS_ENABLED
import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOWN_CALL_NOTIFICATION
import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOWN_CALL_WARNING
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import java.io.IOException import java.io.IOException
import java.util.Arrays import java.util.Arrays
@ -151,6 +154,9 @@ interface TextSecurePreferences {
fun setLastOpenDate() fun setLastOpenDate()
fun hasSeenLinkPreviewSuggestionDialog(): Boolean fun hasSeenLinkPreviewSuggestionDialog(): Boolean
fun setHasSeenLinkPreviewSuggestionDialog() fun setHasSeenLinkPreviewSuggestionDialog()
fun setShownCallWarning(): Boolean
fun setShownCallNotification(): Boolean
fun isCallNotificationsEnabled(): Boolean
fun clearAll() fun clearAll()
companion object { companion object {
@ -228,8 +234,8 @@ interface TextSecurePreferences {
const val LAST_PROFILE_UPDATE_TIME = "pref_last_profile_update_time" const val LAST_PROFILE_UPDATE_TIME = "pref_last_profile_update_time"
const val LAST_OPEN_DATE = "pref_last_open_date" const val LAST_OPEN_DATE = "pref_last_open_date"
const val CALL_NOTIFICATIONS_ENABLED = "pref_call_notifications_enabled" const val CALL_NOTIFICATIONS_ENABLED = "pref_call_notifications_enabled"
private const val SHOWN_CALL_WARNING = "pref_shown_call_warning" // call warning is user-facing warning of enabling calls const val SHOWN_CALL_WARNING = "pref_shown_call_warning" // call warning is user-facing warning of enabling calls
private const val SHOWN_CALL_NOTIFICATION = "pref_shown_call_notification" // call notification is a promp to check privacy settings const val SHOWN_CALL_NOTIFICATION = "pref_shown_call_notification" // call notification is a promp to check privacy settings
@JvmStatic @JvmStatic
fun getLastConfigurationSyncTime(context: Context): Long { fun getLastConfigurationSyncTime(context: Context): Long {
@ -873,6 +879,17 @@ interface TextSecurePreferences {
setBooleanPreference(context, "has_seen_link_preview_suggestion_dialog", true) setBooleanPreference(context, "has_seen_link_preview_suggestion_dialog", true)
} }
@JvmStatic
fun setShownCallWarning(context: Context): Boolean {
val previousValue = getBooleanPreference(context, SHOWN_CALL_WARNING, false)
if (previousValue) {
return false
}
val setValue = true
setBooleanPreference(context, SHOWN_CALL_WARNING, setValue)
return previousValue != setValue
}
@JvmStatic @JvmStatic
fun clearAll(context: Context) { fun clearAll(context: Context) {
getDefaultSharedPreferences(context).edit().clear().commit() getDefaultSharedPreferences(context).edit().clear().commit()
@ -1429,21 +1446,15 @@ class AppTextSecurePreferences @Inject constructor(
setBooleanPreference("has_seen_link_preview_suggestion_dialog", true) setBooleanPreference("has_seen_link_preview_suggestion_dialog", true)
} }
override fun clearAll() { override fun isCallNotificationsEnabled(): Boolean {
getDefaultSharedPreferences(context).edit().clear().commit() return getBooleanPreference(CALL_NOTIFICATIONS_ENABLED, false)
} }
@JvmStatic override fun setShownCallNotification(): Boolean {
fun isCallNotificationsEnabled(context: Context): Boolean { val previousValue = getBooleanPreference(SHOWN_CALL_NOTIFICATION, false)
return getBooleanPreference(context, CALL_NOTIFICATIONS_ENABLED, false)
}
@JvmStatic
fun setShownCallNotification(context: Context): Boolean {
val previousValue = getBooleanPreference(context, SHOWN_CALL_NOTIFICATION, false)
if (previousValue) return false if (previousValue) return false
val setValue = true val setValue = true
setBooleanPreference(context, SHOWN_CALL_NOTIFICATION, setValue) setBooleanPreference(SHOWN_CALL_NOTIFICATION, setValue)
return previousValue != setValue return previousValue != setValue
} }
@ -1452,15 +1463,18 @@ class AppTextSecurePreferences @Inject constructor(
* Set the SHOWN_CALL_WARNING preference to `true` * Set the SHOWN_CALL_WARNING preference to `true`
* Return `true` if the value did update (it was previously unset) * Return `true` if the value did update (it was previously unset)
*/ */
@JvmStatic override fun setShownCallWarning() : Boolean {
fun setShownCallWarning(context: Context) : Boolean { val previousValue = getBooleanPreference(SHOWN_CALL_WARNING, false)
val previousValue = getBooleanPreference(context, SHOWN_CALL_WARNING, false)
if (previousValue) { if (previousValue) {
return false return false
} }
val setValue = true val setValue = true
setBooleanPreference(context, SHOWN_CALL_WARNING, setValue) setBooleanPreference(SHOWN_CALL_WARNING, setValue)
return previousValue != setValue return previousValue != setValue
} }
override fun clearAll() {
getDefaultSharedPreferences(context).edit().clear().commit()
}
} }