mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-25 16:27:38 +00:00
feat: adding call messages for incoming/outgoing/missed
This commit is contained in:
@@ -155,7 +155,7 @@ dependencies {
|
|||||||
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
||||||
}
|
}
|
||||||
|
|
||||||
def canonicalVersionCode = 235
|
def canonicalVersionCode = 236
|
||||||
def canonicalVersionName = "1.12.0-ALPHA3"
|
def canonicalVersionName = "1.12.0-ALPHA3"
|
||||||
|
|
||||||
def postFixSize = 10
|
def postFixSize = 10
|
||||||
|
@@ -161,7 +161,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());
|
callMessageProcessor = new CallMessageProcessor(this, ProcessLifecycleOwner.get().getLifecycle(), storage);
|
||||||
Log.i(TAG, "onCreate()");
|
Log.i(TAG, "onCreate()");
|
||||||
startKovenant();
|
startKovenant();
|
||||||
initializeSecurityProvider();
|
initializeSecurityProvider();
|
||||||
|
@@ -204,7 +204,8 @@ public interface MmsSmsColumns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCallLog(long type) {
|
public static boolean isCallLog(long type) {
|
||||||
return type == INCOMING_CALL_TYPE || type == OUTGOING_CALL_TYPE || type == MISSED_CALL_TYPE;
|
long baseType = type & BASE_TYPE_MASK;
|
||||||
|
return baseType == INCOMING_CALL_TYPE || baseType == OUTGOING_CALL_TYPE || baseType == MISSED_CALL_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isExpirationTimerUpdate(long type) {
|
public static boolean isExpirationTimerUpdate(long type) {
|
||||||
|
@@ -28,6 +28,7 @@ import com.annimon.stream.Stream;
|
|||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
import net.sqlcipher.database.SQLiteStatement;
|
import net.sqlcipher.database.SQLiteStatement;
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType;
|
||||||
import org.session.libsession.messaging.messages.signal.IncomingGroupMessage;
|
import org.session.libsession.messaging.messages.signal.IncomingGroupMessage;
|
||||||
import org.session.libsession.messaging.messages.signal.IncomingTextMessage;
|
import org.session.libsession.messaging.messages.signal.IncomingTextMessage;
|
||||||
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
|
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
|
||||||
@@ -373,6 +374,21 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
if (message.isOpenGroupInvitation()) type |= Types.OPEN_GROUP_INVITATION_BIT;
|
if (message.isOpenGroupInvitation()) type |= Types.OPEN_GROUP_INVITATION_BIT;
|
||||||
|
|
||||||
|
CallMessageType callMessageType = message.getCallType();
|
||||||
|
if (callMessageType != null) {
|
||||||
|
switch (callMessageType) {
|
||||||
|
case CALL_OUTGOING:
|
||||||
|
type |= Types.OUTGOING_CALL_TYPE;
|
||||||
|
break;
|
||||||
|
case CALL_INCOMING:
|
||||||
|
type |= Types.INCOMING_CALL_TYPE;
|
||||||
|
break;
|
||||||
|
case CALL_MISSED:
|
||||||
|
type |= Types.MISSED_CALL_TYPE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Recipient recipient = Recipient.from(context, message.getSender(), true);
|
Recipient recipient = Recipient.from(context, message.getSender(), true);
|
||||||
|
|
||||||
Recipient groupRecipient;
|
Recipient groupRecipient;
|
||||||
@@ -384,7 +400,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean unread = (Util.isDefaultSmsProvider(context) ||
|
boolean unread = (Util.isDefaultSmsProvider(context) ||
|
||||||
message.isSecureMessage() || message.isGroup());
|
message.isSecureMessage() || message.isGroup() || message.isCallInfo());
|
||||||
|
|
||||||
long threadId;
|
long threadId;
|
||||||
|
|
||||||
@@ -441,6 +457,10 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, 0);
|
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<InsertResult> insertCallMessage(IncomingTextMessage message) {
|
||||||
|
return insertMessageInbox(message, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long serverTimestamp) {
|
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long serverTimestamp) {
|
||||||
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp);
|
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.database
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import org.session.libsession.database.StorageProtocol
|
import org.session.libsession.database.StorageProtocol
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
import org.session.libsession.messaging.jobs.*
|
import org.session.libsession.messaging.jobs.*
|
||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
@@ -617,4 +618,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1)
|
database.insertSecureDecryptedMessageInbox(mediaMessage, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun insertCallMessage(senderPublicKey: String, callMessageType: CallMessageType, sentTimestamp: Long) {
|
||||||
|
val database = DatabaseComponent.get(context).smsDatabase()
|
||||||
|
val address = fromSerialized(senderPublicKey)
|
||||||
|
val callMessage = IncomingTextMessage.fromCallInfo(callMessageType, address, Optional.absent(), sentTimestamp)
|
||||||
|
database.insertCallMessage(callMessage)
|
||||||
|
}
|
||||||
}
|
}
|
@@ -120,6 +120,6 @@ public abstract class DisplayRecord {
|
|||||||
public boolean isDeleted() { return MmsSmsColumns.Types.isDeletedMessage(type); }
|
public boolean isDeleted() { return MmsSmsColumns.Types.isDeletedMessage(type); }
|
||||||
|
|
||||||
public boolean isControlMessage() {
|
public boolean isControlMessage() {
|
||||||
return isGroupUpdateMessage() || isExpirationTimerUpdate() || isDataExtractionNotification();
|
return isGroupUpdateMessage() || isExpirationTimerUpdate() || isDataExtractionNotification() || isCallLog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import android.text.style.StyleSpan;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType;
|
||||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
|
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
|
||||||
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
|
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
|
||||||
import org.session.libsession.messaging.utilities.UpdateMessageData;
|
import org.session.libsession.messaging.utilities.UpdateMessageData;
|
||||||
@@ -112,6 +113,9 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||||||
} else if (isDataExtractionNotification()) {
|
} else if (isDataExtractionNotification()) {
|
||||||
if (isScreenshotNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize())));
|
if (isScreenshotNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize())));
|
||||||
else if (isMediaSavedNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize())));
|
else if (isMediaSavedNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize())));
|
||||||
|
} else if (isCallLog()) {
|
||||||
|
CallMessageType callType = isIncomingCall() ? CallMessageType.CALL_INCOMING : isOutgoingCall() ? CallMessageType.CALL_OUTGOING : CallMessageType.CALL_MISSED;
|
||||||
|
return new SpannableString(UpdateMessageBuilder.INSTANCE.buildCallMessage(context, callType, getIndividualRecipient().getAddress().serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SpannableString(getBody());
|
return new SpannableString(getBody());
|
||||||
|
@@ -12,6 +12,7 @@ import android.telephony.PhoneStateListener
|
|||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.FutureTaskListener
|
import org.session.libsession.utilities.FutureTaskListener
|
||||||
import org.session.libsession.utilities.Util
|
import org.session.libsession.utilities.Util
|
||||||
@@ -113,11 +114,12 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
.putExtra(EXTRA_CALL_ID, callId)
|
.putExtra(EXTRA_CALL_ID, callId)
|
||||||
.putExtra(EXTRA_REMOTE_DESCRIPTION, sdp)
|
.putExtra(EXTRA_REMOTE_DESCRIPTION, sdp)
|
||||||
|
|
||||||
fun preOffer(context: Context, address: Address, callId: UUID) =
|
fun preOffer(context: Context, address: Address, callId: UUID, sentTimestamp: Long) =
|
||||||
Intent(context, WebRtcCallService::class.java)
|
Intent(context, WebRtcCallService::class.java)
|
||||||
.setAction(ACTION_PRE_OFFER)
|
.setAction(ACTION_PRE_OFFER)
|
||||||
.putExtra(EXTRA_RECIPIENT_ADDRESS, address)
|
.putExtra(EXTRA_RECIPIENT_ADDRESS, address)
|
||||||
.putExtra(EXTRA_CALL_ID, callId)
|
.putExtra(EXTRA_CALL_ID, callId)
|
||||||
|
.putExtra(EXTRA_TIMESTAMP, sentTimestamp)
|
||||||
|
|
||||||
fun iceCandidates(context: Context, address: Address, iceCandidates: List<IceCandidate>, callId: UUID) =
|
fun iceCandidates(context: Context, address: Address, iceCandidates: List<IceCandidate>, callId: UUID) =
|
||||||
Intent(context, WebRtcCallService::class.java)
|
Intent(context, WebRtcCallService::class.java)
|
||||||
@@ -205,7 +207,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
action == ACTION_OUTGOING_CALL && isIdle() -> handleOutgoingCall(intent)
|
action == ACTION_OUTGOING_CALL && isIdle() -> handleOutgoingCall(intent)
|
||||||
action == ACTION_ANSWER_CALL -> handleAnswerCall(intent)
|
action == ACTION_ANSWER_CALL -> handleAnswerCall(intent)
|
||||||
action == ACTION_DENY_CALL -> handleDenyCall(intent)
|
action == ACTION_DENY_CALL -> handleDenyCall(intent)
|
||||||
action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent, true)
|
action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent)
|
||||||
action == ACTION_REMOTE_HANGUP -> handleRemoteHangup(intent)
|
action == ACTION_REMOTE_HANGUP -> handleRemoteHangup(intent)
|
||||||
action == ACTION_SET_MUTE_AUDIO -> handleSetMuteAudio(intent)
|
action == ACTION_SET_MUTE_AUDIO -> handleSetMuteAudio(intent)
|
||||||
action == ACTION_SET_MUTE_VIDEO -> handleSetMuteVideo(intent)
|
action == ACTION_SET_MUTE_VIDEO -> handleSetMuteVideo(intent)
|
||||||
@@ -311,8 +313,10 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
}
|
}
|
||||||
val callId = getCallId(intent)
|
val callId = getCallId(intent)
|
||||||
val recipient = getRemoteRecipient(intent)
|
val recipient = getRemoteRecipient(intent)
|
||||||
|
val sentTimestamp = intent.getLongExtra(EXTRA_TIMESTAMP, -1)
|
||||||
|
// TODO: check stale call info and don't proceed
|
||||||
setCallInProgressNotification(TYPE_INCOMING_PRE_OFFER, recipient)
|
setCallInProgressNotification(TYPE_INCOMING_PRE_OFFER, recipient)
|
||||||
callManager.onPreOffer(callId, recipient)
|
callManager.onPreOffer(callId, recipient, sentTimestamp)
|
||||||
callManager.postViewModelState(CallViewModel.State.CALL_PRE_INIT)
|
callManager.postViewModelState(CallViewModel.State.CALL_PRE_INIT)
|
||||||
callManager.initializeAudioForCall()
|
callManager.initializeAudioForCall()
|
||||||
callManager.startIncomingRinger()
|
callManager.startIncomingRinger()
|
||||||
@@ -346,7 +350,8 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
if (callManager.currentConnectionState != STATE_IDLE) throw IllegalStateException("Dialing from non-idle")
|
if (callManager.currentConnectionState != STATE_IDLE) throw IllegalStateException("Dialing from non-idle")
|
||||||
|
|
||||||
callManager.postConnectionEvent(STATE_DIALING)
|
callManager.postConnectionEvent(STATE_DIALING)
|
||||||
callManager.recipient = getRemoteRecipient(intent)
|
val recipient = getRemoteRecipient(intent)
|
||||||
|
callManager.recipient = recipient
|
||||||
val callId = UUID.randomUUID()
|
val callId = UUID.randomUUID()
|
||||||
callManager.callId = callId
|
callManager.callId = callId
|
||||||
|
|
||||||
@@ -357,7 +362,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
callManager.initializeAudioForCall()
|
callManager.initializeAudioForCall()
|
||||||
callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING)
|
callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING)
|
||||||
setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
|
setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
|
||||||
// TODO: DatabaseComponent.get(this).insertOutgoingCall(callManager.recipient!!.address)
|
callManager.insertCallMessage(recipient.address.serialize(), CallMessageType.CALL_OUTGOING)
|
||||||
timeoutExecutor.schedule(TimeoutRunnable(callId, this), 2, TimeUnit.MINUTES)
|
timeoutExecutor.schedule(TimeoutRunnable(callId, this), 2, TimeUnit.MINUTES)
|
||||||
|
|
||||||
val expectedState = callManager.currentConnectionState
|
val expectedState = callManager.currentConnectionState
|
||||||
@@ -438,13 +443,13 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
callManager.handleDenyCall()
|
callManager.handleDenyCall()
|
||||||
// DatabaseComponent.get(this).smsDatabase().insertMissedCall(recipient)
|
|
||||||
terminate()
|
terminate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocalHangup(intent: Intent, sendHangup: Boolean) {
|
private fun handleLocalHangup(intent: Intent) {
|
||||||
// TODO: check current call ID and recipient == expected
|
val intentRecipient = getRemoteRecipient(intent)
|
||||||
callManager.handleLocalHangup(sendHangup)
|
val callId = getCallId(intent)
|
||||||
|
callManager.handleLocalHangup(intentRecipient, callId)
|
||||||
terminate()
|
terminate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +501,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
try {
|
try {
|
||||||
val recipient = getRemoteRecipient(intent)
|
val recipient = getRemoteRecipient(intent)
|
||||||
if (callManager.isCurrentUser(recipient) && callManager.currentConnectionState == STATE_LOCAL_RINGING) {
|
if (callManager.isCurrentUser(recipient) && callManager.currentConnectionState == STATE_LOCAL_RINGING) {
|
||||||
handleLocalHangup(intent, false)
|
handleLocalHangup(intent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val callId = getCallId(intent)
|
val callId = getCallId(intent)
|
||||||
@@ -558,7 +563,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
|||||||
|
|
||||||
if (callId == getCallId(intent) && callState !in arrayOf(STATE_CONNECTED)) {
|
if (callId == getCallId(intent) && callState !in arrayOf(STATE_CONNECTED)) {
|
||||||
Log.w(TAG, "Timing out call: $callId")
|
Log.w(TAG, "Timing out call: $callId")
|
||||||
handleLocalHangup(intent, true)
|
handleLocalHangup(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.webrtc
|
|
||||||
|
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
|
||||||
|
|
||||||
interface CallDataListener {
|
|
||||||
fun newCallMessage(callMessage: SignalServiceProtos.CallMessage)
|
|
||||||
}
|
|
@@ -12,6 +12,7 @@ import nl.komponents.kovenant.Promise
|
|||||||
import nl.komponents.kovenant.combine.and
|
import nl.komponents.kovenant.combine.and
|
||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
import org.session.libsession.database.StorageProtocol
|
import org.session.libsession.database.StorageProtocol
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.messages.control.CallMessage
|
import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
@@ -36,8 +37,7 @@ import java.util.*
|
|||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
class CallManager(context: Context, audioManager: AudioManagerCompat, private val storage: StorageProtocol): PeerConnection.Observer,
|
class CallManager(context: Context, audioManager: AudioManagerCompat, private val storage: StorageProtocol): PeerConnection.Observer,
|
||||||
SignalAudioManager.EventListener,
|
SignalAudioManager.EventListener, CameraEventListener, DataChannel.Observer {
|
||||||
CallDataListener, CameraEventListener, DataChannel.Observer {
|
|
||||||
|
|
||||||
enum class CallState {
|
enum class CallState {
|
||||||
STATE_IDLE, STATE_PRE_OFFER, STATE_DIALING, STATE_ANSWERING, STATE_REMOTE_RINGING, STATE_LOCAL_RINGING, STATE_CONNECTED
|
STATE_IDLE, STATE_PRE_OFFER, STATE_DIALING, STATE_ANSWERING, STATE_REMOTE_RINGING, STATE_LOCAL_RINGING, STATE_CONNECTED
|
||||||
@@ -163,10 +163,6 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
_callStateEvents.value = newState
|
_callStateEvents.value = newState
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newCallMessage(callMessage: SignalServiceProtos.CallMessage) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isBusy(context: Context, callId: UUID) = callId != this.callId && (currentConnectionState != CallState.STATE_IDLE
|
fun isBusy(context: Context, callId: UUID) = callId != this.callId && (currentConnectionState != CallState.STATE_IDLE
|
||||||
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE)
|
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE)
|
||||||
|
|
||||||
@@ -355,7 +351,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
localCameraState = newCameraState
|
localCameraState = newCameraState
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPreOffer(callId: UUID, recipient: Recipient) {
|
fun onPreOffer(callId: UUID, recipient: Recipient, sentTimestamp: Long) {
|
||||||
if (preOfferCallData != null) {
|
if (preOfferCallData != null) {
|
||||||
Log.d(TAG, "Received new pre-offer when we are already expecting one")
|
Log.d(TAG, "Received new pre-offer when we are already expecting one")
|
||||||
}
|
}
|
||||||
@@ -363,6 +359,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
this.callId = callId
|
this.callId = callId
|
||||||
preOfferCallData = PreOffer(callId, recipient)
|
preOfferCallData = PreOffer(callId, recipient)
|
||||||
postConnectionEvent(CallState.STATE_PRE_OFFER)
|
postConnectionEvent(CallState.STATE_PRE_OFFER)
|
||||||
|
insertCallMessage(recipient.address.serialize(), CallMessageType.CALL_INCOMING, sentTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onNewOffer(offer: String, callId: UUID, recipient: Recipient): Promise<Unit, Exception> {
|
fun onNewOffer(offer: String, callId: UUID, recipient: Recipient): Promise<Unit, Exception> {
|
||||||
@@ -482,9 +479,16 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
MessageSender.sendNonDurably(CallMessage.endCall(callId), recipient.address)
|
MessageSender.sendNonDurably(CallMessage.endCall(callId), recipient.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleLocalHangup(sendHangup: Boolean) {
|
fun handleLocalHangup(intentRecipient: Recipient, intentCallId: UUID) {
|
||||||
val recipient = recipient ?: return
|
val recipient = recipient ?: return
|
||||||
val callId = callId ?: return
|
val callId = callId ?: return
|
||||||
|
if (intentCallId != callId) {
|
||||||
|
Log.w(TAG,"Processing local hangup for non-active ring call ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentUserPublicKey = storage.getUserPublicKey()
|
||||||
|
val sendHangup = intentRecipient == recipient && recipient.address.serialize() != currentUserPublicKey
|
||||||
|
|
||||||
postViewModelState(CallViewModel.State.CALL_DISCONNECTED)
|
postViewModelState(CallViewModel.State.CALL_DISCONNECTED)
|
||||||
if (sendHangup) {
|
if (sendHangup) {
|
||||||
@@ -492,6 +496,10 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun insertCallMessage(threadPublicKey: String, callMessageType: CallMessageType, sentTimestamp: Long = System.currentTimeMillis()) {
|
||||||
|
storage.insertCallMessage(threadPublicKey, callMessageType, sentTimestamp)
|
||||||
|
}
|
||||||
|
|
||||||
fun handleRemoteHangup() {
|
fun handleRemoteHangup() {
|
||||||
when (currentConnectionState) {
|
when (currentConnectionState) {
|
||||||
CallState.STATE_DIALING,
|
CallState.STATE_DIALING,
|
||||||
|
@@ -7,6 +7,8 @@ import androidx.lifecycle.coroutineScope
|
|||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.session.libsession.database.StorageProtocol
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.messages.control.CallMessage
|
import org.session.libsession.messaging.messages.control.CallMessage
|
||||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
@@ -17,7 +19,7 @@ import org.thoughtcrime.securesms.service.WebRtcCallService
|
|||||||
import org.webrtc.IceCandidate
|
import org.webrtc.IceCandidate
|
||||||
|
|
||||||
|
|
||||||
class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle, private val storage: StorageProtocol) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
lifecycle.coroutineScope.launch(IO) {
|
lifecycle.coroutineScope.launch(IO) {
|
||||||
@@ -26,7 +28,10 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
|||||||
Log.d("Loki", nextMessage.type?.name ?: "CALL MESSAGE RECEIVED")
|
Log.d("Loki", nextMessage.type?.name ?: "CALL MESSAGE RECEIVED")
|
||||||
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) {
|
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) {
|
||||||
Log.d("Loki","Dropping call message if call notifications disabled")
|
Log.d("Loki","Dropping call message if call notifications disabled")
|
||||||
// TODO: maybe insert a message here saying you missed a call due to permissions
|
if (nextMessage.type != PRE_OFFER) continue
|
||||||
|
val sentTimestamp = nextMessage.sentTimestamp ?: continue
|
||||||
|
val sender = nextMessage.sender ?: continue
|
||||||
|
insertMissedCall(sender, sentTimestamp)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
when (nextMessage.type) {
|
when (nextMessage.type) {
|
||||||
@@ -41,6 +46,12 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun insertMissedCall(sender: String, sentTimestamp: Long) {
|
||||||
|
val currentUserPublicKey = storage.getUserPublicKey()
|
||||||
|
if (sender == currentUserPublicKey) return // don't insert a "missed" due to call notifications disabled if it's our own sender
|
||||||
|
storage.insertCallMessage(sender, CallMessageType.CALL_MISSED, sentTimestamp)
|
||||||
|
}
|
||||||
|
|
||||||
private fun incomingHangup(callMessage: CallMessage) {
|
private fun incomingHangup(callMessage: CallMessage) {
|
||||||
val callId = callMessage.callId ?: return
|
val callId = callMessage.callId ?: return
|
||||||
val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId)
|
val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId)
|
||||||
@@ -84,6 +95,7 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
|||||||
context = context,
|
context = context,
|
||||||
address = Address.fromSerialized(recipientAddress),
|
address = Address.fromSerialized(recipientAddress),
|
||||||
callId = callId,
|
callId = callId,
|
||||||
|
sentTimestamp = callMessage.sentTimestamp!!
|
||||||
)
|
)
|
||||||
ContextCompat.startForegroundService(context, incomingIntent)
|
ContextCompat.startForegroundService(context, incomingIntent)
|
||||||
}
|
}
|
||||||
@@ -97,7 +109,7 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
|||||||
address = Address.fromSerialized(recipientAddress),
|
address = Address.fromSerialized(recipientAddress),
|
||||||
sdp = sdp,
|
sdp = sdp,
|
||||||
callId = callId,
|
callId = callId,
|
||||||
callTime = callMessage.sentTimestamp ?: -1L
|
callTime = callMessage.sentTimestamp!!
|
||||||
)
|
)
|
||||||
ContextCompat.startForegroundService(context, incomingIntent)
|
ContextCompat.startForegroundService(context, incomingIntent)
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ package org.session.libsession.database
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||||
import org.session.libsession.messaging.jobs.Job
|
import org.session.libsession.messaging.jobs.Job
|
||||||
@@ -153,4 +154,5 @@ interface StorageProtocol {
|
|||||||
*/
|
*/
|
||||||
fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long?
|
fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long?
|
||||||
fun insertDataExtractionNotificationMessage(senderPublicKey: String, message: DataExtractionNotificationInfoMessage, sentTimestamp: Long)
|
fun insertDataExtractionNotificationMessage(senderPublicKey: String, message: DataExtractionNotificationInfoMessage, sentTimestamp: Long)
|
||||||
|
fun insertCallMessage(senderPublicKey: String, callMessageType: CallMessageType, sentTimestamp: Long)
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
package org.session.libsession.messaging.calls
|
||||||
|
|
||||||
|
enum class CallMessageType {
|
||||||
|
CALL_MISSED,
|
||||||
|
CALL_INCOMING,
|
||||||
|
CALL_OUTGOING
|
||||||
|
}
|
@@ -5,6 +5,7 @@ import android.os.Parcelable;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType;
|
||||||
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation;
|
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation;
|
||||||
import org.session.libsession.messaging.messages.visible.VisibleMessage;
|
import org.session.libsession.messaging.messages.visible.VisibleMessage;
|
||||||
import org.session.libsession.utilities.Address;
|
import org.session.libsession.utilities.Address;
|
||||||
@@ -41,12 +42,19 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresInMillis;
|
private final long expiresInMillis;
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
|
private final int callType;
|
||||||
|
|
||||||
private boolean isOpenGroupInvitation = false;
|
private boolean isOpenGroupInvitation = false;
|
||||||
|
|
||||||
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
|
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
|
||||||
String encodedBody, Optional<SignalServiceGroup> group,
|
String encodedBody, Optional<SignalServiceGroup> group,
|
||||||
long expiresInMillis, boolean unidentified)
|
long expiresInMillis, boolean unidentified) {
|
||||||
|
this(sender, senderDeviceId, sentTimestampMillis, encodedBody, group, expiresInMillis, unidentified, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
|
||||||
|
String encodedBody, Optional<SignalServiceGroup> group,
|
||||||
|
long expiresInMillis, boolean unidentified, int callType)
|
||||||
{
|
{
|
||||||
this.message = encodedBody;
|
this.message = encodedBody;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
@@ -60,6 +68,7 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.subscriptionId = -1;
|
this.subscriptionId = -1;
|
||||||
this.expiresInMillis = expiresInMillis;
|
this.expiresInMillis = expiresInMillis;
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
this.callType = callType;
|
||||||
|
|
||||||
if (group.isPresent()) {
|
if (group.isPresent()) {
|
||||||
this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get()));
|
this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get()));
|
||||||
@@ -82,6 +91,8 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.subscriptionId = in.readInt();
|
this.subscriptionId = in.readInt();
|
||||||
this.expiresInMillis = in.readLong();
|
this.expiresInMillis = in.readLong();
|
||||||
this.unidentified = in.readInt() == 1;
|
this.unidentified = in.readInt() == 1;
|
||||||
|
this.isOpenGroupInvitation = in.readInt() == 1;
|
||||||
|
this.callType = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
||||||
@@ -98,7 +109,8 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.subscriptionId = base.getSubscriptionId();
|
this.subscriptionId = base.getSubscriptionId();
|
||||||
this.expiresInMillis = base.getExpiresIn();
|
this.expiresInMillis = base.getExpiresIn();
|
||||||
this.unidentified = base.isUnidentified();
|
this.unidentified = base.isUnidentified();
|
||||||
this.isOpenGroupInvitation= base.isOpenGroupInvitation();
|
this.isOpenGroupInvitation = base.isOpenGroupInvitation();
|
||||||
|
this.callType = base.callType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncomingTextMessage from(VisibleMessage message,
|
public static IncomingTextMessage from(VisibleMessage message,
|
||||||
@@ -121,6 +133,13 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
return incomingTextMessage;
|
return incomingTextMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IncomingTextMessage fromCallInfo(CallMessageType callMessageType,
|
||||||
|
Address sender,
|
||||||
|
Optional<SignalServiceGroup> group,
|
||||||
|
long sentTimestamp) {
|
||||||
|
return new IncomingTextMessage(sender, 1, sentTimestamp, null, group, 0, false, callMessageType.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
public int getSubscriptionId() {
|
public int getSubscriptionId() {
|
||||||
return subscriptionId;
|
return subscriptionId;
|
||||||
}
|
}
|
||||||
@@ -183,6 +202,18 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
|
|
||||||
public boolean isOpenGroupInvitation() { return isOpenGroupInvitation; }
|
public boolean isOpenGroupInvitation() { return isOpenGroupInvitation; }
|
||||||
|
|
||||||
|
public boolean isCallInfo() {
|
||||||
|
int callMessageTypeLength = CallMessageType.values().length;
|
||||||
|
return callType >= 0 && callType < callMessageTypeLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public CallMessageType getCallType() {
|
||||||
|
int callTypeLength = CallMessageType.values().length;
|
||||||
|
if (callType < 0 || callType >= callTypeLength) return null;
|
||||||
|
return CallMessageType.values()[callType];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -202,5 +233,7 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
out.writeInt(push ? 1 : 0);
|
out.writeInt(push ? 1 : 0);
|
||||||
out.writeInt(subscriptionId);
|
out.writeInt(subscriptionId);
|
||||||
out.writeInt(unidentified ? 1 : 0);
|
out.writeInt(unidentified ? 1 : 0);
|
||||||
|
out.writeInt(isOpenGroupInvitation ? 1 : 0);
|
||||||
|
out.writeInt(callType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package org.session.libsession.messaging.utilities
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import org.session.libsession.R
|
import org.session.libsession.R
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
||||||
import org.session.libsession.utilities.ExpirationUtil
|
import org.session.libsession.utilities.ExpirationUtil
|
||||||
@@ -102,4 +103,17 @@ object UpdateMessageBuilder {
|
|||||||
context.getString(R.string.MessageRecord_media_saved_by_s, senderName)
|
context.getString(R.string.MessageRecord_media_saved_by_s, senderName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildCallMessage(context: Context, type: CallMessageType, sender: String): String {
|
||||||
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val senderName = storage.getContactWithSessionID(sender)?.displayName(Contact.ContactContext.REGULAR) ?: sender
|
||||||
|
return when (type) {
|
||||||
|
CallMessageType.CALL_MISSED ->
|
||||||
|
context.getString(R.string.MessageRecord_missed_call_from, senderName)
|
||||||
|
CallMessageType.CALL_INCOMING ->
|
||||||
|
context.getString(R.string.MessageRecord_called_s, senderName)
|
||||||
|
CallMessageType.CALL_OUTGOING ->
|
||||||
|
context.getString(R.string.MessageRecord_s_called_you, senderName)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user