joinedMembers, boolean isCallFull) {
+ SignalExecutors.BOUNDED.execute(() -> DatabaseFactory.getSmsDatabase(context).insertOrUpdateGroupCall(groupId,
+ Recipient.self().getId(),
+ System.currentTimeMillis(),
+ groupCallEraId,
+ joinedMembers,
+ isCallFull));
+ }
+
+ public void sendCallMessage(@NonNull final RemotePeer remotePeer,
+ @NonNull final SignalServiceCallMessage callMessage)
+ {
+ networkExecutor.execute(() -> {
+ Recipient recipient = Recipient.resolved(remotePeer.getId());
+ if (recipient.isBlocked()) {
+ return;
+ }
+
+ try {
+ messageSender.sendCallMessage(RecipientUtil.toSignalServiceAddress(context, recipient),
+ UnidentifiedAccessUtil.getAccessFor(context, recipient),
+ callMessage);
+ process((s, p) -> p.handleMessageSentSuccess(s, remotePeer.getCallId()));
+ } catch (UntrustedIdentityException e) {
+ processSendMessageFailureWithChangeDetection(remotePeer,
+ (s, p) -> p.handleMessageSentError(s,
+ remotePeer.getCallId(),
+ UNTRUSTED_IDENTITY,
+ Optional.fromNullable(e.getIdentityKey())));
+ } catch (IOException e) {
+ processSendMessageFailureWithChangeDetection(remotePeer,
+ (s, p) -> p.handleMessageSentError(s,
+ remotePeer.getCallId(),
+ e instanceof UnregisteredUserException ? NO_SUCH_USER : NETWORK_FAILURE,
+ Optional.absent()));
+ }
+ });
+ }
+
+ private void processSendMessageFailureWithChangeDetection(@NonNull RemotePeer remotePeer,
+ @NonNull ProcessAction failureProcessAction)
+ {
+ process((s, p) -> {
+ RemotePeer activePeer = s.getCallInfoState().getActivePeer();
+
+ boolean stateChanged = activePeer == null ||
+ remotePeer.getState() != activePeer.getState() ||
+ !remotePeer.getCallId().equals(activePeer.getCallId());
+
+ if (stateChanged) {
+ return p.handleMessageSentSuccess(s, remotePeer.getCallId());
+ } else {
+ return failureProcessAction.process(s, p);
+ }
+ });
+ }
+
+ interface ProcessAction {
+ @NonNull WebRtcServiceState process(@NonNull WebRtcServiceState currentState, @NonNull WebRtcActionProcessor processor);
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java
index 9456a42863..20ab3b8f12 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.service.webrtc;
import android.content.Context;
-import android.content.Intent;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
@@ -10,6 +9,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
+import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
@@ -21,10 +21,8 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.ringrtc.CallState;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraState;
-import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.WebRtcData.CallMetadata;
-import org.thoughtcrime.securesms.service.webrtc.WebRtcData.HttpData;
import org.thoughtcrime.securesms.service.webrtc.WebRtcData.OfferMetadata;
import org.thoughtcrime.securesms.service.webrtc.WebRtcData.ReceivedOfferMetadata;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
@@ -41,116 +39,23 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
-import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ACCEPT_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_BANDWIDTH_MODE_UPDATE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_BLUETOOTH_CHANGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_CALL_CONCLUDED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_CALL_CONNECTED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_CAMERA_SWITCH_COMPLETED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_DENY_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_CONNECTION_FAILURE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_INTERNAL_FAILURE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_BUSY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_GLARE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_HANGUP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_HANGUP_ACCEPTED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_HANGUP_BUSY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_HANGUP_DECLINED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_REMOTE_HANGUP_NEED_PERMISSION;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_SIGNALING_FAILURE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ENDED_TIMEOUT;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_FLIP_CAMERA;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_APPROVE_SAFETY_CHANGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_CALL_ENDED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_CALL_PEEK;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_JOINED_MEMBERSHIP_CHANGED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_LOCAL_DEVICE_STATE_CHANGED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_MESSAGE_SENT_ERROR;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_REMOTE_DEVICE_STATE_CHANGED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_REQUEST_MEMBERSHIP_PROOF;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_REQUEST_UPDATE_MEMBERS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_GROUP_UPDATE_RENDERED_RESOLUTIONS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_HTTP_FAILURE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_HTTP_SUCCESS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_IS_IN_CALL_QUERY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_LOCAL_HANGUP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_LOCAL_RINGING;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_MESSAGE_SENT_ERROR;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_MESSAGE_SENT_SUCCESS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_NETWORK_CHANGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ORIENTATION_CHANGED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_OUTGOING_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_PRE_JOIN_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVED_OFFER_EXPIRED;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVED_OFFER_WHILE_ACTIVE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_ANSWER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_BUSY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_HANGUP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_ICE_CANDIDATES;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_OFFER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVE_OPAQUE_MESSAGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_REMOTE_RINGING;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_REMOTE_VIDEO_ENABLE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SCREEN_OFF;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_ANSWER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_BUSY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_HANGUP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_ICE_CANDIDATES;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_OFFER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SEND_OPAQUE_MESSAGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SETUP_FAILURE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SET_AUDIO_BLUETOOTH;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SET_AUDIO_SPEAKER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SET_ENABLE_VIDEO;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_SET_MUTE_AUDIO;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_START_INCOMING_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_START_OUTGOING_CALL;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_TURN_SERVER_UPDATE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_WIRED_HEADSET_CHANGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ANSWER_WITH_VIDEO;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_BLUETOOTH;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_IS_ALWAYS_TURN;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_MUTE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_RECIPIENT_IDS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_RESULT_RECEIVER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_SPEAKER;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.AnswerMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.HangupMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.OpaqueMessageMetadata;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcData.ReceivedAnswerMetadata;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getAvailable;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getBroadcastFlag;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getCallId;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getCameraState;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getEnable;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getErrorCallState;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getErrorIdentityKey;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getGroupCallEndReason;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getGroupCallHash;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getGroupMembershipToken;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIceCandidates;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIceServers;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getNullableRemotePeerFromMap;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getOfferMessageType;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getOrientationDegrees;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRemotePeer;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRemotePeerFromMap;
/**
* Base WebRTC action processor and core of the calling state machine. As actions (as intents)
* are sent to the service, they are passed to an instance of the current state's action processor.
* Based on the state of the system, the action processor will either handle the event or do nothing.
- *
+ *
* For example, the {@link OutgoingCallActionProcessor} responds to the the
* {@link #handleReceivedBusy(WebRtcServiceState, CallMetadata)} event but no others do.
- *
- * Processing of the actions occur in {@link #processAction(String, Intent, WebRtcServiceState)} and
+ *
+ * Processing of the actions occur in by calls from {@link SignalCallManager} and
* result in atomic state updates that are returned to the caller. Part of the state change can be
* the replacement of the current action processor.
*/
@@ -161,7 +66,7 @@ public abstract class WebRtcActionProcessor {
protected final String tag;
public WebRtcActionProcessor(@NonNull WebRtcInteractor webRtcInteractor, @NonNull String tag) {
- this.context = webRtcInteractor.getWebRtcCallService();
+ this.context = webRtcInteractor.getContext();
this.webRtcInteractor = webRtcInteractor;
this.tag = tag;
}
@@ -170,102 +75,6 @@ public abstract class WebRtcActionProcessor {
return tag;
}
- public @NonNull WebRtcServiceState processAction(@NonNull String action, @NonNull Intent intent, @NonNull WebRtcServiceState currentState) {
- switch (action) {
- case ACTION_IS_IN_CALL_QUERY: return handleIsInCallQuery(currentState, intent.getParcelableExtra(EXTRA_RESULT_RECEIVER));
-
- // Pre-Join Actions
- case ACTION_PRE_JOIN_CALL: return handlePreJoinCall(currentState, getRemotePeer(intent));
- case ACTION_CANCEL_PRE_JOIN_CALL: return handleCancelPreJoinCall(currentState);
-
- // Outgoing Call Actions
- case ACTION_OUTGOING_CALL: return handleOutgoingCall(currentState, getRemotePeer(intent), getOfferMessageType(intent));
- case ACTION_START_OUTGOING_CALL: return handleStartOutgoingCall(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_SEND_OFFER: return handleSendOffer(currentState, CallMetadata.fromIntent(intent), OfferMetadata.fromIntent(intent), getBroadcastFlag(intent));
- case ACTION_REMOTE_RINGING: return handleRemoteRinging(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_RECEIVE_ANSWER: return handleReceivedAnswer(currentState, CallMetadata.fromIntent(intent), AnswerMetadata.fromIntent(intent), ReceivedAnswerMetadata.fromIntent(intent));
- case ACTION_RECEIVE_BUSY: return handleReceivedBusy(currentState, CallMetadata.fromIntent(intent));
-
- // Incoming Call Actions
- case ACTION_RECEIVE_OFFER: return handleReceivedOffer(currentState, CallMetadata.fromIntent(intent), OfferMetadata.fromIntent(intent), ReceivedOfferMetadata.fromIntent(intent));
- case ACTION_RECEIVED_OFFER_EXPIRED: return handleReceivedOfferExpired(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_START_INCOMING_CALL: return handleStartIncomingCall(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_ACCEPT_CALL: return handleAcceptCall(currentState, intent.getBooleanExtra(EXTRA_ANSWER_WITH_VIDEO, false));
- case ACTION_LOCAL_RINGING: return handleLocalRinging(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_DENY_CALL: return handleDenyCall(currentState);
- case ACTION_SEND_ANSWER: return handleSendAnswer(currentState, CallMetadata.fromIntent(intent), AnswerMetadata.fromIntent(intent), getBroadcastFlag(intent));
-
- // Active Call Actions
- case ACTION_CALL_CONNECTED: return handleCallConnected(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_RECEIVED_OFFER_WHILE_ACTIVE: return handleReceivedOfferWhileActive(currentState, getRemotePeerFromMap(intent, currentState));
- case ACTION_SEND_BUSY: return handleSendBusy(currentState, CallMetadata.fromIntent(intent), getBroadcastFlag(intent));
- case ACTION_CALL_CONCLUDED: return handleCallConcluded(currentState, getNullableRemotePeerFromMap(intent, currentState));
- case ACTION_REMOTE_VIDEO_ENABLE: return handleRemoteVideoEnable(currentState, getEnable(intent));
- case ACTION_RECEIVE_HANGUP: return handleReceivedHangup(currentState, CallMetadata.fromIntent(intent), HangupMetadata.fromIntent(intent));
- case ACTION_LOCAL_HANGUP: return handleLocalHangup(currentState);
- case ACTION_SEND_HANGUP: return handleSendHangup(currentState, CallMetadata.fromIntent(intent), HangupMetadata.fromIntent(intent), getBroadcastFlag(intent));
- case ACTION_MESSAGE_SENT_SUCCESS: return handleMessageSentSuccess(currentState, getCallId(intent));
- case ACTION_MESSAGE_SENT_ERROR: return handleMessageSentError(currentState, getCallId(intent), getErrorCallState(intent), getErrorIdentityKey(intent));
-
- // Call Setup Actions
- case ACTION_RECEIVE_ICE_CANDIDATES: return handleReceivedIceCandidates(currentState, CallMetadata.fromIntent(intent), getIceCandidates(intent));
- case ACTION_SEND_ICE_CANDIDATES: return handleSendIceCandidates(currentState, CallMetadata.fromIntent(intent), getBroadcastFlag(intent), getIceCandidates(intent));
- case ACTION_TURN_SERVER_UPDATE: return handleTurnServerUpdate(currentState, getIceServers(intent), intent.getBooleanExtra(EXTRA_IS_ALWAYS_TURN, false));
-
- // Local Device Actions
- case ACTION_SET_ENABLE_VIDEO: return handleSetEnableVideo(currentState, getEnable(intent));
- case ACTION_SET_MUTE_AUDIO: return handleSetMuteAudio(currentState, intent.getBooleanExtra(EXTRA_MUTE, false));
- case ACTION_FLIP_CAMERA: return handleSetCameraFlip(currentState);
- case ACTION_SCREEN_OFF: return handleScreenOffChange(currentState);
- case ACTION_WIRED_HEADSET_CHANGE: return handleWiredHeadsetChange(currentState, getAvailable(intent));
- case ACTION_SET_AUDIO_SPEAKER: return handleSetSpeakerAudio(currentState, intent.getBooleanExtra(EXTRA_SPEAKER, false));
- case ACTION_SET_AUDIO_BLUETOOTH: return handleSetBluetoothAudio(currentState, intent.getBooleanExtra(EXTRA_BLUETOOTH, false));
- case ACTION_BLUETOOTH_CHANGE: return handleBluetoothChange(currentState, getAvailable(intent));
- case ACTION_CAMERA_SWITCH_COMPLETED: return handleCameraSwitchCompleted(currentState, getCameraState(intent));
- case ACTION_NETWORK_CHANGE: return handleNetworkChanged(currentState, getAvailable(intent));
- case ACTION_BANDWIDTH_MODE_UPDATE: return handleBandwidthModeUpdate(currentState);
- case ACTION_ORIENTATION_CHANGED: return handleOrientationChanged(currentState, getOrientationDegrees(intent));
-
- // End Call Actions
- case ACTION_ENDED_REMOTE_HANGUP:
- case ACTION_ENDED_REMOTE_HANGUP_ACCEPTED:
- case ACTION_ENDED_REMOTE_HANGUP_BUSY:
- case ACTION_ENDED_REMOTE_HANGUP_DECLINED:
- case ACTION_ENDED_REMOTE_BUSY:
- case ACTION_ENDED_REMOTE_HANGUP_NEED_PERMISSION:
- case ACTION_ENDED_REMOTE_GLARE: return handleEndedRemote(currentState, action, getRemotePeerFromMap(intent, currentState));
-
- // End Call Failure Actions
- case ACTION_ENDED_TIMEOUT:
- case ACTION_ENDED_INTERNAL_FAILURE:
- case ACTION_ENDED_SIGNALING_FAILURE:
- case ACTION_ENDED_CONNECTION_FAILURE: return handleEnded(currentState, action, getRemotePeerFromMap(intent, currentState));
-
- // Local Call Failure Actions
- case ACTION_SETUP_FAILURE: return handleSetupFailure(currentState, getCallId(intent));
-
- // Group Calling
- case ACTION_GROUP_LOCAL_DEVICE_STATE_CHANGED: return handleGroupLocalDeviceStateChanged(currentState);
- case ACTION_GROUP_REMOTE_DEVICE_STATE_CHANGED: return handleGroupRemoteDeviceStateChanged(currentState);
- case ACTION_GROUP_JOINED_MEMBERSHIP_CHANGED: return handleGroupJoinedMembershipChanged(currentState);
- case ACTION_GROUP_REQUEST_MEMBERSHIP_PROOF: return handleGroupRequestMembershipProof(currentState, getGroupCallHash(intent), getGroupMembershipToken(intent));
- case ACTION_GROUP_REQUEST_UPDATE_MEMBERS: return handleGroupRequestUpdateMembers(currentState);
- case ACTION_GROUP_UPDATE_RENDERED_RESOLUTIONS: return handleUpdateRenderedResolutions(currentState);
- case ACTION_GROUP_CALL_ENDED: return handleGroupCallEnded(currentState, getGroupCallHash(intent), getGroupCallEndReason(intent));
- case ACTION_GROUP_CALL_PEEK: return handleGroupCallPeek(currentState, getRemotePeer(intent));
- case ACTION_GROUP_MESSAGE_SENT_ERROR: return handleGroupMessageSentError(currentState, getRemotePeer(intent), getErrorCallState(intent), getErrorIdentityKey(intent));
- case ACTION_GROUP_APPROVE_SAFETY_CHANGE: return handleGroupApproveSafetyNumberChange(currentState, RecipientId.fromSerializedList(intent.getStringExtra(EXTRA_RECIPIENT_IDS)));
-
- case ACTION_HTTP_SUCCESS: return handleHttpSuccess(currentState, HttpData.fromIntent(intent));
- case ACTION_HTTP_FAILURE: return handleHttpFailure(currentState, HttpData.fromIntent(intent));
-
- case ACTION_SEND_OPAQUE_MESSAGE: return handleSendOpaqueMessage(currentState, OpaqueMessageMetadata.fromIntent(intent));
- case ACTION_RECEIVE_OPAQUE_MESSAGE: return handleReceivedOpaqueMessage(currentState, OpaqueMessageMetadata.fromIntent(intent));
- }
-
- return currentState;
- }
-
protected @NonNull WebRtcServiceState handleIsInCallQuery(@NonNull WebRtcServiceState currentState, @Nullable ResultReceiver resultReceiver) {
if (resultReceiver != null) {
resultReceiver.send(0, null);
@@ -337,21 +146,21 @@ public abstract class WebRtcActionProcessor {
if (TelephonyUtil.isAnyPstnLineBusy(context)) {
Log.i(tag, "PSTN line is busy.");
currentState = currentState.getActionProcessor().handleSendBusy(currentState, callMetadata, true);
- webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), true, receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
+ webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
return currentState;
}
if (!RecipientUtil.isCallRequestAccepted(context.getApplicationContext(), callMetadata.getRemotePeer().getRecipient())) {
Log.w(tag, "Caller is untrusted.");
currentState = currentState.getActionProcessor().handleSendHangup(currentState, callMetadata, WebRtcData.HangupMetadata.fromType(HangupMessage.Type.NEED_PERMISSION), true);
- webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), true, receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
+ webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
return currentState;
}
if (offerMetadata.getOpaque() == null) {
Log.w(tag, "Opaque data is required.");
currentState = currentState.getActionProcessor().handleSendHangup(currentState, callMetadata, WebRtcData.HangupMetadata.fromType(HangupMessage.Type.NORMAL), true);
- webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), true, receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
+ webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
return currentState;
}
@@ -397,7 +206,7 @@ public abstract class WebRtcActionProcessor {
{
Log.i(tag, "handleReceivedOfferExpired(): call_id: " + remotePeer.getCallId());
- webRtcInteractor.insertMissedCall(remotePeer, true, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer());
+ webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer());
return terminate(currentState, remotePeer);
}
@@ -475,7 +284,7 @@ public abstract class WebRtcActionProcessor {
try {
webRtcInteractor.getCallManager().receivedHangup(callMetadata.getCallId(), callMetadata.getRemoteDevice(), hangupMetadata.getCallHangupType(), hangupMetadata.getDeviceId());
- } catch (CallException e) {
+ } catch (CallException e) {
return callFailure(currentState, "receivedHangup() failed: ", e);
}
@@ -515,7 +324,8 @@ public abstract class WebRtcActionProcessor {
protected @NonNull WebRtcServiceState handleMessageSentError(@NonNull WebRtcServiceState currentState,
@NonNull CallId callId,
@NonNull WebRtcViewModel.State errorCallState,
- @NonNull Optional identityKey) {
+ @NonNull Optional identityKey)
+ {
Log.w(tag, "handleMessageSentError():");
try {
@@ -552,18 +362,13 @@ public abstract class WebRtcActionProcessor {
//region Call setup
- protected @NonNull WebRtcServiceState handleSendIceCandidates(@NonNull WebRtcServiceState currentState, @NonNull CallMetadata callMetadata, boolean broadcast, @NonNull ArrayList iceCandidates) {
+ protected @NonNull WebRtcServiceState handleSendIceCandidates(@NonNull WebRtcServiceState currentState, @NonNull CallMetadata callMetadata, boolean broadcast, @NonNull List iceCandidates) {
Log.i(tag, "handleSendIceCandidates not processed");
return currentState;
}
- protected @NonNull WebRtcServiceState handleReceivedIceCandidates(@NonNull WebRtcServiceState currentState, @NonNull CallMetadata callMetadata, @NonNull ArrayList iceCandidateParcels) {
- Log.i(tag, "handleReceivedIceCandidates(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice()) + ", count: " + iceCandidateParcels.size());
-
- LinkedList iceCandidates = new LinkedList<>();
- for (IceCandidateParcel parcel : iceCandidateParcels) {
- iceCandidates.add(parcel.getIceCandidate());
- }
+ protected @NonNull WebRtcServiceState handleReceivedIceCandidates(@NonNull WebRtcServiceState currentState, @NonNull CallMetadata callMetadata, @NonNull List iceCandidates) {
+ Log.i(tag, "handleReceivedIceCandidates(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice()) + ", count: " + iceCandidates.size());
try {
webRtcInteractor.getCallManager().receivedIceCandidates(callMetadata.getCallId(), callMetadata.getRemoteDevice(), iceCandidates);
@@ -659,7 +464,7 @@ public abstract class WebRtcActionProcessor {
//region End call
- protected @NonNull WebRtcServiceState handleEndedRemote(@NonNull WebRtcServiceState currentState, @NonNull String action, @NonNull RemotePeer remotePeer) {
+ protected @NonNull WebRtcServiceState handleEndedRemote(@NonNull WebRtcServiceState currentState, @NonNull CallManager.CallEvent endedRemoteEvent, @NonNull RemotePeer remotePeer) {
Log.i(tag, "handleEndedRemote not processed");
return currentState;
}
@@ -668,7 +473,7 @@ public abstract class WebRtcActionProcessor {
//region End call failure
- protected @NonNull WebRtcServiceState handleEnded(@NonNull WebRtcServiceState currentState, @NonNull String action, @NonNull RemotePeer remotePeer) {
+ protected @NonNull WebRtcServiceState handleEnded(@NonNull WebRtcServiceState currentState, @NonNull CallManager.CallEvent endedEvent, @NonNull RemotePeer remotePeer) {
Log.i(tag, "handleEnded not processed");
return currentState;
}
@@ -677,7 +482,7 @@ public abstract class WebRtcActionProcessor {
//region Local call failure
- protected @NonNull WebRtcServiceState handleSetupFailure(@NonNull WebRtcServiceState currentState, @NonNull CallId callId) {
+ protected @NonNull WebRtcServiceState handleSetupFailure(@NonNull WebRtcServiceState currentState, @NonNull CallId callId) {
Log.i(tag, "handleSetupFailure not processed");
return currentState;
}
@@ -786,11 +591,6 @@ public abstract class WebRtcActionProcessor {
return currentState;
}
- protected @NonNull WebRtcServiceState handleGroupCallPeek(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
- webRtcInteractor.peekGroupCall(remotePeer.getId());
- return currentState;
- }
-
protected @NonNull WebRtcServiceState handleGroupMessageSentError(@NonNull WebRtcServiceState currentState,
@NonNull RemotePeer remotePeer,
@NonNull WebRtcViewModel.State errorCallState,
@@ -809,30 +609,6 @@ public abstract class WebRtcActionProcessor {
//endregion
- protected @NonNull WebRtcServiceState handleHttpSuccess(@NonNull WebRtcServiceState currentState, @NonNull HttpData httpData) {
- try {
- webRtcInteractor.getCallManager().receivedHttpResponse(httpData.getRequestId(), httpData.getStatus(), httpData.getBody() != null ? httpData.getBody() : new byte[0]);
- } catch (CallException e) {
- return callFailure(currentState, "Unable to process received http response", e);
- }
- return currentState;
- }
-
- protected @NonNull WebRtcServiceState handleHttpFailure(@NonNull WebRtcServiceState currentState, @NonNull HttpData httpData) {
- try {
- webRtcInteractor.getCallManager().httpRequestFailed(httpData.getRequestId());
- } catch (CallException e) {
- return callFailure(currentState, "Unable to process received http response", e);
- }
- return currentState;
- }
-
- protected @NonNull WebRtcServiceState handleSendOpaqueMessage(@NonNull WebRtcServiceState currentState, @NonNull OpaqueMessageMetadata opaqueMessageMetadata) {
- Log.i(tag, "handleSendOpaqueMessage not processed");
-
- return currentState;
- }
-
protected @NonNull WebRtcServiceState handleReceivedOpaqueMessage(@NonNull WebRtcServiceState currentState, @NonNull OpaqueMessageMetadata opaqueMessageMetadata) {
Log.i(tag, "handleReceivedOpaqueMessage not processed");
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcCallService.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcCallService.java
new file mode 100644
index 0000000000..c967214765
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcCallService.java
@@ -0,0 +1,304 @@
+package org.thoughtcrime.securesms.service.webrtc;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Build;
+import android.os.IBinder;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+
+import org.signal.core.util.logging.Log;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
+import org.thoughtcrime.securesms.recipients.Recipient;
+import org.thoughtcrime.securesms.recipients.RecipientId;
+import org.thoughtcrime.securesms.util.TelephonyUtil;
+import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
+import org.thoughtcrime.securesms.webrtc.UncaughtExceptionHandlerManager;
+import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager;
+import org.thoughtcrime.securesms.webrtc.locks.LockManager;
+
+import java.util.Objects;
+
+/**
+ * Provide a foreground service for {@link SignalCallManager} to leverage to run in the background when necessary. Also
+ * provides devices listeners needed for during a call (i.e., bluetooth, power button).
+ */
+public final class WebRtcCallService extends Service implements BluetoothStateManager.BluetoothStateListener {
+
+ private static final String TAG = Log.tag(WebRtcCallService.class);
+
+ private static final String ACTION_UPDATE = "UPDATE";
+ private static final String ACTION_STOP = "STOP";
+ private static final String ACTION_DENY_CALL = "DENY_CALL";
+ private static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP";
+ private static final String ACTION_WANTS_BLUETOOTH = "WANTS_BLUETOOTH";
+ private static final String ACTION_CHANGE_POWER_BUTTON = "CHANGE_POWER_BUTTON";
+
+ private static final String EXTRA_UPDATE_TYPE = "UPDATE_TYPE";
+ private static final String EXTRA_RECIPIENT_ID = "RECIPIENT_ID";
+ private static final String EXTRA_ENABLED = "ENABLED";
+
+ private SignalCallManager callManager;
+
+ private WiredHeadsetStateReceiver wiredHeadsetStateReceiver;
+ private NetworkReceiver networkReceiver;
+ private PowerButtonReceiver powerButtonReceiver;
+ private UncaughtExceptionHandlerManager uncaughtExceptionHandlerManager;
+ private PhoneStateListener hangUpRtcOnDeviceCallAnswered;
+ private BluetoothStateManager bluetoothStateManager;
+
+ public static void update(@NonNull Context context, int type, @NonNull RecipientId recipientId) {
+ Intent intent = new Intent(context, WebRtcCallService.class);
+ intent.setAction(ACTION_UPDATE)
+ .putExtra(EXTRA_UPDATE_TYPE, type)
+ .putExtra(EXTRA_RECIPIENT_ID, recipientId);
+
+ ContextCompat.startForegroundService(context, intent);
+ }
+
+ public static void stop(@NonNull Context context) {
+ Intent intent = new Intent(context, WebRtcCallService.class);
+ intent.setAction(ACTION_STOP);
+
+ context.startService(intent);
+ }
+
+ public static @NonNull Intent denyCallIntent(@NonNull Context context) {
+ return new Intent(context, WebRtcCallService.class).setAction(ACTION_DENY_CALL);
+ }
+
+ public static @NonNull Intent hangupIntent(@NonNull Context context) {
+ return new Intent(context, WebRtcCallService.class).setAction(ACTION_LOCAL_HANGUP);
+ }
+
+ public static void setWantsBluetoothConnection(@NonNull Context context, boolean enabled) {
+ Intent intent = new Intent(context, WebRtcCallService.class);
+ intent.setAction(ACTION_WANTS_BLUETOOTH)
+ .putExtra(EXTRA_ENABLED, enabled);
+
+ context.startService(intent);
+ }
+
+ public static void changePowerButtonReceiver(@NonNull Context context, boolean register) {
+ Intent intent = new Intent(context, WebRtcCallService.class);
+ intent.setAction(ACTION_CHANGE_POWER_BUTTON)
+ .putExtra(EXTRA_ENABLED, register);
+
+ context.startService(intent);
+ }
+
+ @Override
+ public void onCreate() {
+ Log.v(TAG, "onCreate");
+ super.onCreate();
+ this.callManager = ApplicationDependencies.getSignalCallManager();
+ this.bluetoothStateManager = new BluetoothStateManager(this, this);
+ this.hangUpRtcOnDeviceCallAnswered = new HangUpRtcOnPstnCallAnsweredListener();
+
+ registerUncaughtExceptionHandler();
+ registerWiredHeadsetStateReceiver();
+ registerNetworkReceiver();
+
+ TelephonyUtil.getManager(this)
+ .listen(hangUpRtcOnDeviceCallAnswered, PhoneStateListener.LISTEN_CALL_STATE);
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.v(TAG, "onDestroy");
+ super.onDestroy();
+
+ if (uncaughtExceptionHandlerManager != null) {
+ uncaughtExceptionHandlerManager.unregister();
+ }
+
+ if (bluetoothStateManager != null) {
+ bluetoothStateManager.onDestroy();
+ }
+
+ if (wiredHeadsetStateReceiver != null) {
+ unregisterReceiver(wiredHeadsetStateReceiver);
+ wiredHeadsetStateReceiver = null;
+ }
+
+ unregisterNetworkReceiver();
+ unregisterNetworkReceiver();
+
+ TelephonyUtil.getManager(this)
+ .listen(hangUpRtcOnDeviceCallAnswered, PhoneStateListener.LISTEN_NONE);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null || intent.getAction() == null) {
+ return START_NOT_STICKY;
+ }
+
+ Log.i(TAG, "action: " + intent.getAction());
+
+ switch (intent.getAction()) {
+ case ACTION_UPDATE:
+ setCallInProgressNotification(intent.getIntExtra(EXTRA_UPDATE_TYPE, 0),
+ Objects.requireNonNull(intent.getParcelableExtra(EXTRA_RECIPIENT_ID)));
+ return START_STICKY;
+ case ACTION_WANTS_BLUETOOTH:
+ if (bluetoothStateManager != null) {
+ bluetoothStateManager.setWantsConnection(intent.getBooleanExtra(EXTRA_ENABLED, false));
+ }
+ return START_STICKY;
+ case ACTION_CHANGE_POWER_BUTTON:
+ if (intent.getBooleanExtra(EXTRA_ENABLED, false)) {
+ registerPowerButtonReceiver();
+ } else {
+ unregisterPowerButtonReceiver();
+ }
+ return START_STICKY;
+ case ACTION_STOP:
+ stopSelf();
+ stopForeground(true);
+ return START_NOT_STICKY;
+ case ACTION_DENY_CALL:
+ callManager.denyCall();
+ return START_NOT_STICKY;
+ case ACTION_LOCAL_HANGUP:
+ callManager.localHangup();
+ return START_NOT_STICKY;
+ default:
+ throw new AssertionError("Unknown action: " + intent.getAction());
+ }
+ }
+
+ public void setCallInProgressNotification(int type, @NonNull RecipientId id) {
+ startForeground(CallNotificationBuilder.getNotificationId(type),
+ CallNotificationBuilder.getCallInProgressNotification(this, type, Recipient.resolved(id)));
+ }
+
+ private void registerUncaughtExceptionHandler() {
+ uncaughtExceptionHandlerManager = new UncaughtExceptionHandlerManager();
+ uncaughtExceptionHandlerManager.registerHandler(new ProximityLockRelease(callManager.getLockManager()));
+ }
+
+ private void registerWiredHeadsetStateReceiver() {
+ wiredHeadsetStateReceiver = new WiredHeadsetStateReceiver();
+
+ String action;
+
+ if (Build.VERSION.SDK_INT >= 21) {
+ action = AudioManager.ACTION_HEADSET_PLUG;
+ } else {
+ action = Intent.ACTION_HEADSET_PLUG;
+ }
+
+ registerReceiver(wiredHeadsetStateReceiver, new IntentFilter(action));
+ }
+
+ private void registerNetworkReceiver() {
+ if (networkReceiver == null) {
+ networkReceiver = new NetworkReceiver();
+
+ registerReceiver(networkReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+ }
+ }
+
+ private void unregisterNetworkReceiver() {
+ if (networkReceiver != null) {
+ unregisterReceiver(networkReceiver);
+
+ networkReceiver = null;
+ }
+ }
+
+ public void registerPowerButtonReceiver() {
+ if (powerButtonReceiver == null) {
+ powerButtonReceiver = new PowerButtonReceiver();
+
+ registerReceiver(powerButtonReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+ }
+ }
+
+ public void unregisterPowerButtonReceiver() {
+ if (powerButtonReceiver != null) {
+ unregisterReceiver(powerButtonReceiver);
+
+ powerButtonReceiver = null;
+ }
+ }
+
+ @Override
+ public @Nullable IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onBluetoothStateChanged(boolean isAvailable) {
+ callManager.bluetoothChange(isAvailable);
+ }
+
+ private class HangUpRtcOnPstnCallAnsweredListener extends PhoneStateListener {
+ @Override
+ public void onCallStateChanged(int state, @NonNull String phoneNumber) {
+ super.onCallStateChanged(state, phoneNumber);
+ if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
+ hangup();
+ Log.i(TAG, "Device phone call ended Signal call.");
+ }
+ }
+
+ private void hangup() {
+ callManager.localHangup();
+ }
+ }
+
+ private static class WiredHeadsetStateReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ int state = intent.getIntExtra("state", -1);
+
+ ApplicationDependencies.getSignalCallManager().wiredHeadsetChange(state != 0);
+ }
+ }
+
+ private static class NetworkReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+
+ ApplicationDependencies.getSignalCallManager().networkChange(activeNetworkInfo != null && activeNetworkInfo.isConnected());
+ ApplicationDependencies.getSignalCallManager().bandwidthModeUpdate();
+ }
+ }
+
+ private static class PowerButtonReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ ApplicationDependencies.getSignalCallManager().screenOff();
+ }
+ }
+ }
+
+ private static class ProximityLockRelease implements Thread.UncaughtExceptionHandler {
+ private final LockManager lockManager;
+
+ private ProximityLockRelease(@NonNull LockManager lockManager) {
+ this.lockManager = lockManager;
+ }
+
+ @Override
+ public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
+ Log.i(TAG, "Uncaught exception - releasing proximity lock", throwable);
+ lockManager.updatePhoneState(LockManager.PhoneState.IDLE);
+ }
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java
index 2c04559ce2..e67a2383d6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java
@@ -1,53 +1,30 @@
package org.thoughtcrime.securesms.service.webrtc;
-import android.content.Intent;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
-import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import java.util.UUID;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_CALL_ERA_ID;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_CALL_UPDATE_GROUP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_CALL_UPDATE_SENDER;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HANGUP_DEVICE_ID;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HANGUP_IS_LEGACY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HANGUP_TYPE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HTTP_REQUEST_ID;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HTTP_RESPONSE_BODY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_HTTP_RESPONSE_STATUS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_MESSAGE_AGE_SECONDS;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_SERVER_DELIVERED_TIMESTAMP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_SERVER_RECEIVED_TIMESTAMP;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRecipientId;
-import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRemoteDevice;
-
/**
- * Collection of classes to ease parsing data from intents and passing said data
- * around.
+ * Collection of classes to ease passing calling data around.
*/
public class WebRtcData {
/**
* Low-level metadata Information about the call.
*/
- static class CallMetadata {
+ public static class CallMetadata {
private final @NonNull RemotePeer remotePeer;
private final @NonNull CallId callId;
private final int remoteDevice;
- public static @NonNull CallMetadata fromIntent(@NonNull Intent intent) {
- return new CallMetadata(WebRtcIntentParser.getRemotePeer(intent), WebRtcIntentParser.getCallId(intent), WebRtcIntentParser.getRemoteDevice(intent));
- }
-
- private CallMetadata(@NonNull RemotePeer remotePeer, @NonNull CallId callId, int remoteDevice) {
+ public CallMetadata(@NonNull RemotePeer remotePeer, @NonNull CallId callId, int remoteDevice) {
this.remotePeer = remotePeer;
this.callId = callId;
this.remoteDevice = remoteDevice;
@@ -69,18 +46,12 @@ public class WebRtcData {
/**
* Metadata for a call offer to be sent or received.
*/
- static class OfferMetadata {
+ public static class OfferMetadata {
private final @Nullable byte[] opaque;
private final @Nullable String sdp;
private final @NonNull OfferMessage.Type offerType;
- static @NonNull OfferMetadata fromIntent(@NonNull Intent intent) {
- return new OfferMetadata(WebRtcIntentParser.getOfferOpaque(intent),
- WebRtcIntentParser.getOfferSdp(intent),
- WebRtcIntentParser.getOfferMessageType(intent));
- }
-
- private OfferMetadata(@Nullable byte[] opaque, @Nullable String sdp, @NonNull OfferMessage.Type offerType) {
+ public OfferMetadata(@Nullable byte[] opaque, @Nullable String sdp, @NonNull OfferMessage.Type offerType) {
this.opaque = opaque;
this.sdp = sdp;
this.offerType = offerType;
@@ -102,20 +73,13 @@ public class WebRtcData {
/**
* Additional metadata for a received call.
*/
- static class ReceivedOfferMetadata {
+ public static class ReceivedOfferMetadata {
private final @NonNull byte[] remoteIdentityKey;
private final long serverReceivedTimestamp;
private final long serverDeliveredTimestamp;
private final boolean isMultiRing;
- static @NonNull ReceivedOfferMetadata fromIntent(@NonNull Intent intent) {
- return new ReceivedOfferMetadata(WebRtcIntentParser.getRemoteIdentityKey(intent),
- intent.getLongExtra(EXTRA_SERVER_RECEIVED_TIMESTAMP, -1),
- intent.getLongExtra(EXTRA_SERVER_DELIVERED_TIMESTAMP, -1),
- WebRtcIntentParser.getMultiRingFlag(intent));
- }
-
- ReceivedOfferMetadata(@NonNull byte[] remoteIdentityKey, long serverReceivedTimestamp, long serverDeliveredTimestamp, boolean isMultiRing) {
+ public ReceivedOfferMetadata(@NonNull byte[] remoteIdentityKey, long serverReceivedTimestamp, long serverDeliveredTimestamp, boolean isMultiRing) {
this.remoteIdentityKey = remoteIdentityKey;
this.serverReceivedTimestamp = serverReceivedTimestamp;
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
@@ -142,17 +106,13 @@ public class WebRtcData {
/**
* Metadata for an answer to be sent or received.
*/
- static class AnswerMetadata {
- private final @Nullable byte[] opaque;
- private final @Nullable String sdp;
+ public static class AnswerMetadata {
+ private final @Nullable byte[] opaque;
+ private final @Nullable String sdp;
- static @NonNull AnswerMetadata fromIntent(@NonNull Intent intent) {
- return new AnswerMetadata(WebRtcIntentParser.getAnswerOpaque(intent), WebRtcIntentParser.getAnswerSdp(intent));
- }
-
- private AnswerMetadata(@Nullable byte[] opaque, @Nullable String sdp) {
- this.opaque = opaque;
- this.sdp = sdp;
+ public AnswerMetadata(@Nullable byte[] opaque, @Nullable String sdp) {
+ this.opaque = opaque;
+ this.sdp = sdp;
}
@Nullable byte[] getOpaque() {
@@ -167,17 +127,13 @@ public class WebRtcData {
/**
* Additional metadata for a received answer.
*/
- static class ReceivedAnswerMetadata {
+ public static class ReceivedAnswerMetadata {
private final @NonNull byte[] remoteIdentityKey;
private final boolean isMultiRing;
- static @NonNull ReceivedAnswerMetadata fromIntent(@NonNull Intent intent) {
- return new ReceivedAnswerMetadata(WebRtcIntentParser.getRemoteIdentityKey(intent), WebRtcIntentParser.getMultiRingFlag(intent));
- }
-
- ReceivedAnswerMetadata(@NonNull byte[] remoteIdentityKey, boolean isMultiRing) {
- this.remoteIdentityKey = remoteIdentityKey;
- this.isMultiRing = isMultiRing;
+ public ReceivedAnswerMetadata(@NonNull byte[] remoteIdentityKey, boolean isMultiRing) {
+ this.remoteIdentityKey = remoteIdentityKey;
+ this.isMultiRing = isMultiRing;
}
@NonNull byte[] getRemoteIdentityKey() {
@@ -192,22 +148,16 @@ public class WebRtcData {
/**
* Metadata for a remote or local hangup.
*/
- static class HangupMetadata {
+ public static class HangupMetadata {
private final @NonNull HangupMessage.Type type;
private final boolean isLegacy;
private final int deviceId;
- static @NonNull HangupMetadata fromIntent(@NonNull Intent intent) {
- return new HangupMetadata(HangupMessage.Type.fromCode(intent.getStringExtra(EXTRA_HANGUP_TYPE)),
- intent.getBooleanExtra(EXTRA_HANGUP_IS_LEGACY, true),
- intent.getIntExtra(EXTRA_HANGUP_DEVICE_ID, 0));
- }
-
static @NonNull HangupMetadata fromType(@NonNull HangupMessage.Type type) {
return new HangupMetadata(type, true, 0);
}
- HangupMetadata(@NonNull HangupMessage.Type type, boolean isLegacy, int deviceId) {
+ public HangupMetadata(@NonNull HangupMessage.Type type, boolean isLegacy, int deviceId) {
this.type = type;
this.isLegacy = isLegacy;
this.deviceId = deviceId;
@@ -237,56 +187,16 @@ public class WebRtcData {
}
}
- /**
- * Http response data.
- */
- static class HttpData {
- private final long requestId;
- private final int status;
- private final byte[] body;
-
- static @NonNull HttpData fromIntent(@NonNull Intent intent) {
- return new HttpData(intent.getLongExtra(EXTRA_HTTP_REQUEST_ID, -1),
- intent.getIntExtra(EXTRA_HTTP_RESPONSE_STATUS, -1),
- intent.getByteArrayExtra(EXTRA_HTTP_RESPONSE_BODY));
- }
-
- HttpData(long requestId, int status, @Nullable byte[] body) {
- this.requestId = requestId;
- this.status = status;
- this.body = body;
- }
-
- long getRequestId() {
- return requestId;
- }
-
- int getStatus() {
- return status;
- }
-
- @Nullable byte[] getBody() {
- return body;
- }
- }
-
/**
* An opaque calling message.
*/
- static class OpaqueMessageMetadata {
+ public static class OpaqueMessageMetadata {
private final UUID uuid;
private final byte[] opaque;
private final int remoteDeviceId;
private final long messageAgeSeconds;
- static @NonNull OpaqueMessageMetadata fromIntent(@NonNull Intent intent) {
- return new OpaqueMessageMetadata(WebRtcIntentParser.getUuid(intent),
- WebRtcIntentParser.getOpaque(intent),
- getRemoteDevice(intent),
- intent.getLongExtra(EXTRA_MESSAGE_AGE_SECONDS, 0));
- }
-
- OpaqueMessageMetadata(@NonNull UUID uuid, @NonNull byte[] opaque, int remoteDeviceId, long messageAgeSeconds) {
+ public OpaqueMessageMetadata(@NonNull UUID uuid, @NonNull byte[] opaque, int remoteDeviceId, long messageAgeSeconds) {
this.uuid = uuid;
this.opaque = opaque;
this.remoteDeviceId = remoteDeviceId;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java
deleted file mode 100644
index 9da8a2f41b..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package org.thoughtcrime.securesms.service.webrtc;
-
-import android.content.Intent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.signal.core.util.logging.Log;
-import org.signal.ringrtc.CallId;
-import org.signal.ringrtc.GroupCall;
-import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
-import org.thoughtcrime.securesms.events.WebRtcViewModel;
-import org.thoughtcrime.securesms.recipients.RecipientId;
-import org.thoughtcrime.securesms.ringrtc.CameraState;
-import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
-import org.thoughtcrime.securesms.ringrtc.RemotePeer;
-import org.thoughtcrime.securesms.ringrtc.TurnServerInfoParcel;
-import org.thoughtcrime.securesms.service.WebRtcCallService;
-import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
-import org.webrtc.PeerConnection;
-import org.whispersystems.libsignal.IdentityKey;
-import org.whispersystems.libsignal.util.guava.Optional;
-import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
-import org.whispersystems.signalservice.api.util.UuidUtil;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
-
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ANSWER_OPAQUE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ANSWER_SDP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_AVAILABLE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_BROADCAST;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_CALL_ID;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_CAMERA_STATE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ENABLE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ERROR_CALL_STATE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ERROR_IDENTITY_KEY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_CALL_END_REASON;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_CALL_HASH;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_GROUP_EXTERNAL_TOKEN;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ICE_CANDIDATES;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_MULTI_RING;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_OPAQUE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_SDP;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_TYPE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OPAQUE_MESSAGE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ORIENTATION_DEGREES;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_DEVICE;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_IDENTITY_KEY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_PEER_KEY;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_TURN_SERVER_INFO;
-import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_UUID;
-
-/**
- * Helper to parse the various attributes out of intents passed to the service.
- */
-public final class WebRtcIntentParser {
-
- private static final String TAG = Log.tag(WebRtcIntentParser.class);
-
- private WebRtcIntentParser() {}
-
- public static @NonNull CallId getCallId(@NonNull Intent intent) {
- return new CallId(intent.getLongExtra(EXTRA_CALL_ID, -1));
- }
-
- public static int getRemoteDevice(@NonNull Intent intent) {
- return intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
- }
-
- public static @NonNull RemotePeer getRemotePeer(@NonNull Intent intent) {
- RemotePeer remotePeer = intent.getParcelableExtra(WebRtcCallService.EXTRA_REMOTE_PEER);
- if (remotePeer == null) {
- throw new AssertionError("No RemotePeer in intent!");
- }
- return remotePeer;
- }
-
- public static @NonNull RemotePeer getRemotePeerFromMap(@NonNull Intent intent, @NonNull WebRtcServiceState currentState) {
- RemotePeer remotePeer = getNullableRemotePeerFromMap(intent, currentState);
-
- if (remotePeer == null) {
- throw new AssertionError("No RemotePeer in map for key: " + getRemotePeerKey(intent) + "!");
- }
-
- return remotePeer;
- }
-
- public static @Nullable RemotePeer getNullableRemotePeerFromMap(@NonNull Intent intent, @NonNull WebRtcServiceState currentState) {
- return currentState.getCallInfoState().getPeer(getRemotePeerKey(intent));
- }
-
- public static int getRemotePeerKey(@NonNull Intent intent) {
- if (!intent.hasExtra(EXTRA_REMOTE_PEER_KEY)) {
- throw new AssertionError("No RemotePeer key in intent!");
- }
-
- // The default of -1 should never be applied since the key exists.
- return intent.getIntExtra(EXTRA_REMOTE_PEER_KEY, -1);
- }
-
- public static boolean getMultiRingFlag(@NonNull Intent intent) {
- return intent.getBooleanExtra(EXTRA_MULTI_RING, false);
- }
-
- public static @NonNull byte[] getRemoteIdentityKey(@NonNull Intent intent) {
- return Objects.requireNonNull(intent.getByteArrayExtra(EXTRA_REMOTE_IDENTITY_KEY));
- }
-
- public static @Nullable String getAnswerSdp(@NonNull Intent intent) {
- return intent.getStringExtra(EXTRA_ANSWER_SDP);
- }
-
- public static @Nullable String getOfferSdp(@NonNull Intent intent) {
- return intent.getStringExtra(EXTRA_OFFER_SDP);
- }
-
- public static @Nullable byte[] getAnswerOpaque(@NonNull Intent intent) {
- return intent.getByteArrayExtra(EXTRA_ANSWER_OPAQUE);
- }
-
- public static @Nullable byte[] getOfferOpaque(@NonNull Intent intent) {
- return intent.getByteArrayExtra(EXTRA_OFFER_OPAQUE);
- }
-
- public static @NonNull byte[] getOpaque(@NonNull Intent intent) {
- return Objects.requireNonNull(intent.getByteArrayExtra(EXTRA_OPAQUE_MESSAGE));
- }
-
- public static @NonNull UUID getUuid(@NonNull Intent intent) {
- return UuidUtil.parseOrThrow(intent.getStringExtra(EXTRA_UUID));
- }
-
- public static boolean getBroadcastFlag(@NonNull Intent intent) {
- return intent.getBooleanExtra(EXTRA_BROADCAST, false);
- }
-
- public static boolean getAvailable(@NonNull Intent intent) {
- return intent.getBooleanExtra(EXTRA_AVAILABLE, false);
- }
-
- public static int getOrientationDegrees(@NonNull Intent intent) {
- return intent.getIntExtra(EXTRA_ORIENTATION_DEGREES, 0);
- }
-
- public static @NonNull ArrayList getIceCandidates(@NonNull Intent intent) {
- return Objects.requireNonNull(intent.getParcelableArrayListExtra(EXTRA_ICE_CANDIDATES));
- }
-
- public static @NonNull List getIceServers(@NonNull Intent intent) {
- TurnServerInfoParcel turnServerInfoParcel = Objects.requireNonNull(intent.getParcelableExtra(EXTRA_TURN_SERVER_INFO));
- List iceServers = new LinkedList<>();
- iceServers.add(PeerConnection.IceServer.builder("stun:stun1.l.google.com:19302").createIceServer());
- for (String url : turnServerInfoParcel.getUrls()) {
- Log.i(TAG, "ice_server: " + url);
- if (url.startsWith("turn")) {
- iceServers.add(PeerConnection.IceServer.builder(url)
- .setUsername(turnServerInfoParcel.getUsername())
- .setPassword(turnServerInfoParcel.getPassword())
- .createIceServer());
- } else {
- iceServers.add(PeerConnection.IceServer.builder(url).createIceServer());
- }
- }
- return iceServers;
- }
-
- public static @NonNull OfferMessage.Type getOfferMessageType(@NonNull Intent intent) {
- return OfferMessage.Type.fromCode(intent.getStringExtra(EXTRA_OFFER_TYPE));
- }
-
- public static boolean getEnable(@NonNull Intent intent) {
- return intent.getBooleanExtra(EXTRA_ENABLE, false);
- }
-
- public static @NonNull byte[] getGroupMembershipToken(@NonNull Intent intent) {
- return Objects.requireNonNull(intent.getByteArrayExtra(EXTRA_GROUP_EXTERNAL_TOKEN));
- }
-
- public static @NonNull CameraState getCameraState(@NonNull Intent intent) {
- return Objects.requireNonNull(intent.getParcelableExtra(EXTRA_CAMERA_STATE));
- }
-
- public static @NonNull WebRtcViewModel.State getErrorCallState(@NonNull Intent intent) {
- return (WebRtcViewModel.State) Objects.requireNonNull(intent.getSerializableExtra(EXTRA_ERROR_CALL_STATE));
- }
-
- public static @NonNull Optional getErrorIdentityKey(@NonNull Intent intent) {
- IdentityKeyParcelable identityKeyParcelable = intent.getParcelableExtra(EXTRA_ERROR_IDENTITY_KEY);
- if (identityKeyParcelable != null) {
- return Optional.fromNullable(identityKeyParcelable.get());
- }
- return Optional.absent();
- }
-
- public static int getGroupCallHash(@NonNull Intent intent) {
- return intent.getIntExtra(EXTRA_GROUP_CALL_HASH, 0);
- }
-
- public static @NonNull GroupCall.GroupCallEndReason getGroupCallEndReason(@NonNull Intent intent) {
- int ordinal = intent.getIntExtra(EXTRA_GROUP_CALL_END_REASON, -1);
-
- if (ordinal >= 0 && ordinal < GroupCall.GroupCallEndReason.values().length) {
- return GroupCall.GroupCallEndReason.values()[ordinal];
- }
-
- return GroupCall.GroupCallEndReason.DEVICE_EXPLICITLY_DISCONNECTED;
- }
-
- public static @NonNull RecipientId getRecipientId(@NonNull Intent intent, @NonNull String name) {
- return RecipientId.from(Objects.requireNonNull(intent.getStringExtra(name)));
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java
index 8dd7693a72..64695ca9dd 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java
@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.service.webrtc;
+import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
@@ -11,10 +12,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.ringrtc.CameraEventListener;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
-import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.AppForegroundObserver;
-import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager;
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
@@ -30,32 +29,33 @@ import java.util.UUID;
*/
public class WebRtcInteractor {
- @NonNull private final WebRtcCallService webRtcCallService;
- @NonNull private final CallManager callManager;
+ @NonNull private final Context context;
+ @NonNull private final SignalCallManager signalCallManager;
@NonNull private final LockManager lockManager;
@NonNull private final SignalAudioManager audioManager;
- @NonNull private final BluetoothStateManager bluetoothStateManager;
@NonNull private final CameraEventListener cameraEventListener;
@NonNull private final GroupCall.Observer groupCallObserver;
@NonNull private final AppForegroundObserver.Listener foregroundListener;
- public WebRtcInteractor(@NonNull WebRtcCallService webRtcCallService,
- @NonNull CallManager callManager,
+ public WebRtcInteractor(@NonNull Context context,
+ @NonNull SignalCallManager signalCallManager,
@NonNull LockManager lockManager,
@NonNull SignalAudioManager audioManager,
- @NonNull BluetoothStateManager bluetoothStateManager,
@NonNull CameraEventListener cameraEventListener,
@NonNull GroupCall.Observer groupCallObserver,
@NonNull AppForegroundObserver.Listener foregroundListener)
{
- this.webRtcCallService = webRtcCallService;
- this.callManager = callManager;
- this.lockManager = lockManager;
- this.audioManager = audioManager;
- this.bluetoothStateManager = bluetoothStateManager;
- this.cameraEventListener = cameraEventListener;
- this.groupCallObserver = groupCallObserver;
- this.foregroundListener = foregroundListener;
+ this.context = context;
+ this.signalCallManager = signalCallManager;
+ this.lockManager = lockManager;
+ this.audioManager = audioManager;
+ this.cameraEventListener = cameraEventListener;
+ this.groupCallObserver = groupCallObserver;
+ this.foregroundListener = foregroundListener;
+ }
+
+ @NonNull Context getContext() {
+ return context;
}
@NonNull CameraEventListener getCameraEventListener() {
@@ -63,11 +63,7 @@ public class WebRtcInteractor {
}
@NonNull CallManager getCallManager() {
- return callManager;
- }
-
- @NonNull WebRtcCallService getWebRtcCallService() {
- return webRtcCallService;
+ return signalCallManager.getRingRtcCallManager();
}
@NonNull GroupCall.Observer getGroupCallObserver() {
@@ -79,63 +75,59 @@ public class WebRtcInteractor {
}
void setWantsBluetoothConnection(boolean enabled) {
- bluetoothStateManager.setWantsConnection(enabled);
+ WebRtcCallService.setWantsBluetoothConnection(context, enabled);
}
void updatePhoneState(@NonNull LockManager.PhoneState phoneState) {
lockManager.updatePhoneState(phoneState);
}
- void sendMessage(@NonNull WebRtcServiceState state) {
- webRtcCallService.sendMessage(state);
+ void postStateUpdate(@NonNull WebRtcServiceState state) {
+ signalCallManager.postStateUpdate(state);
}
void sendCallMessage(@NonNull RemotePeer remotePeer, @NonNull SignalServiceCallMessage callMessage) {
- webRtcCallService.sendCallMessage(remotePeer, callMessage);
- }
-
- void sendOpaqueCallMessage(@NonNull UUID uuid, @NonNull SignalServiceCallMessage callMessage) {
- webRtcCallService.sendOpaqueCallMessage(uuid, callMessage);
+ signalCallManager.sendCallMessage(remotePeer, callMessage);
}
void sendGroupCallMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId) {
- webRtcCallService.sendGroupCallMessage(recipient, groupCallEraId);
+ signalCallManager.sendGroupCallUpdateMessage(recipient, groupCallEraId);
}
void updateGroupCallUpdateMessage(@NonNull RecipientId groupId, @Nullable String groupCallEraId, @NonNull Collection joinedMembers, boolean isCallFull) {
- webRtcCallService.updateGroupCallUpdateMessage(groupId, groupCallEraId, joinedMembers, isCallFull);
+ signalCallManager.updateGroupCallUpdateMessage(groupId, groupCallEraId, joinedMembers, isCallFull);
}
void setCallInProgressNotification(int type, @NonNull RemotePeer remotePeer) {
- webRtcCallService.setCallInProgressNotification(type, remotePeer.getRecipient());
+ WebRtcCallService.update(context, type, remotePeer.getRecipient().getId());
}
void setCallInProgressNotification(int type, @NonNull Recipient recipient) {
- webRtcCallService.setCallInProgressNotification(type, recipient);
+ WebRtcCallService.update(context, type, recipient.getId());
}
void retrieveTurnServers(@NonNull RemotePeer remotePeer) {
- webRtcCallService.retrieveTurnServers(remotePeer);
+ signalCallManager.retrieveTurnServers(remotePeer);
}
void stopForegroundService() {
- webRtcCallService.stopForeground(true);
+ WebRtcCallService.stop(context);
}
- void insertMissedCall(@NonNull RemotePeer remotePeer, boolean signal, long timestamp, boolean isVideoOffer) {
- webRtcCallService.insertMissedCall(remotePeer, signal, timestamp, isVideoOffer);
+ void insertMissedCall(@NonNull RemotePeer remotePeer, long timestamp, boolean isVideoOffer) {
+ signalCallManager.insertMissedCall(remotePeer, true, timestamp, isVideoOffer);
}
boolean startWebRtcCallActivityIfPossible() {
- return webRtcCallService.startCallCardActivityIfPossible();
+ return signalCallManager.startCallCardActivityIfPossible();
}
void registerPowerButtonReceiver() {
- webRtcCallService.registerPowerButtonReceiver();
+ WebRtcCallService.changePowerButtonReceiver(context, true);
}
void unregisterPowerButtonReceiver() {
- webRtcCallService.unregisterPowerButtonReceiver();
+ WebRtcCallService.changePowerButtonReceiver(context, false);
}
void silenceIncomingRinger() {
@@ -150,8 +142,8 @@ public class WebRtcInteractor {
audioManager.startIncomingRinger(ringtoneUri, vibrate);
}
- void startOutgoingRinger(@NonNull OutgoingRinger.Type type) {
- audioManager.startOutgoingRinger(type);
+ void startOutgoingRinger() {
+ audioManager.startOutgoingRinger(OutgoingRinger.Type.RINGING);
}
void stopAudio(boolean playDisconnect) {
@@ -163,6 +155,6 @@ public class WebRtcInteractor {
}
void peekGroupCall(@NonNull RecipientId recipientId) {
- webRtcCallService.peekGroupCall(recipientId);
+ signalCallManager.peekGroupCall(recipientId);
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java
index 52d07a43b0..989553a747 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
/**
@@ -42,6 +43,27 @@ public final class WebRtcUtil {
return offerType == OfferMessage.Type.VIDEO_CALL ? CallManager.CallMediaType.VIDEO_CALL : CallManager.CallMediaType.AUDIO_CALL;
}
+ public static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@NonNull CallManager.CallMediaType callMediaType) {
+ return callMediaType == CallManager.CallMediaType.VIDEO_CALL ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL;
+ }
+
+ public static @NonNull HangupMessage.Type getHangupTypeFromCallHangupType(@NonNull CallManager.HangupType hangupType) {
+ switch (hangupType) {
+ case ACCEPTED:
+ return HangupMessage.Type.ACCEPTED;
+ case BUSY:
+ return HangupMessage.Type.BUSY;
+ case NORMAL:
+ return HangupMessage.Type.NORMAL;
+ case DECLINED:
+ return HangupMessage.Type.DECLINED;
+ case NEED_PERMISSION:
+ return HangupMessage.Type.NEED_PERMISSION;
+ default:
+ throw new IllegalArgumentException("Unexpected hangup type: " + hangupType);
+ }
+ }
+
public static void enableSpeakerPhoneIfNeeded(@NonNull Context context, boolean enable) {
if (!enable) {
return;
@@ -49,7 +71,7 @@ public final class WebRtcUtil {
AudioManager androidAudioManager = ServiceUtil.getAudioManager(context);
//noinspection deprecation
- boolean shouldEnable = !(androidAudioManager.isSpeakerphoneOn() || androidAudioManager.isBluetoothScoOn() || androidAudioManager.isWiredHeadsetOn());
+ boolean shouldEnable = !(androidAudioManager.isSpeakerphoneOn() || androidAudioManager.isBluetoothScoOn() || androidAudioManager.isWiredHeadsetOn());
if (shouldEnable) {
androidAudioManager.setSpeakerphoneOn(true);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java b/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java
index f077f8afb8..55ca1057fb 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java
@@ -86,7 +86,7 @@ public final class AppForegroundObserver {
}
public interface Listener {
- void onForeground();
- void onBackground();
+ default void onForeground() {}
+ default void onBackground() {}
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
index e876785628..3d14f34ab3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
@@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining.GroupJoinBottomSheetDialogFragment;
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining.GroupJoinUpdateRequiredBottomSheetDialogFragment;
@@ -34,11 +35,8 @@ import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.proxy.ProxyBottomSheetFragment;
import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.ringrtc.RemotePeer;
-import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
-import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
public class CommunicationActions {
@@ -53,7 +51,7 @@ public class CommunicationActions {
return;
}
- WebRtcCallService.isCallActive(activity, new ResultReceiver(new Handler(Looper.getMainLooper())) {
+ ApplicationDependencies.getSignalCallManager().isCallActive(new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == 1) {
@@ -79,7 +77,7 @@ public class CommunicationActions {
return;
}
- WebRtcCallService.isCallActive(activity, new ResultReceiver(new Handler(Looper.getMainLooper())) {
+ ApplicationDependencies.getSignalCallManager().isCallActive(new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
startCallInternal(activity, recipient, resultCode != 1);
@@ -248,11 +246,7 @@ public class CommunicationActions {
R.drawable.ic_mic_solid_24)
.withPermanentDenialDialog(activity.getString(R.string.ConversationActivity__to_call_s_signal_needs_access_to_your_microphone, recipient.getDisplayName(activity)))
.onAllGranted(() -> {
- Intent intent = new Intent(activity, WebRtcCallService.class);
- intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
- .putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(recipient.getId()))
- .putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.AUDIO_CALL.getCode());
- activity.startService(intent);
+ ApplicationDependencies.getSignalCallManager().startOutgoingAudioCall(recipient);
MessageSender.onMessageSent();
@@ -274,11 +268,7 @@ public class CommunicationActions {
R.drawable.ic_video_solid_24_tinted)
.withPermanentDenialDialog(activity.getString(R.string.ConversationActivity_signal_needs_the_microphone_and_camera_permissions_in_order_to_call_s, recipient.getDisplayName(activity)))
.onAllGranted(() -> {
- Intent intent = new Intent(activity, WebRtcCallService.class);
- intent.setAction(WebRtcCallService.ACTION_PRE_JOIN_CALL)
- .putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(recipient.getId()))
- .putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.VIDEO_CALL.getCode());
- activity.startService(intent);
+ ApplicationDependencies.getSignalCallManager().startPreJoinCall(recipient);
Intent activityIntent = new Intent(activity, WebRtcCallActivity.class);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java
index a2c682d503..96b1d52b5f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java
@@ -11,13 +11,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
-import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.service.WebRtcCallService;
+import org.thoughtcrime.securesms.service.webrtc.WebRtcCallService;
/**
* Manages the state of the WebRtc items in the Android notification bar.
@@ -53,7 +52,7 @@ public class CallNotificationBuilder {
builder.setPriority(NotificationCompat.PRIORITY_MIN);
} else if (type == TYPE_INCOMING_RINGING) {
builder.setContentText(context.getString(R.string.NotificationBarManager__incoming_signal_call));
- builder.addAction(getServiceNotificationAction(context, WebRtcCallService.ACTION_DENY_CALL, R.drawable.ic_close_grey600_32dp, R.string.NotificationBarManager__deny_call));
+ builder.addAction(getServiceNotificationAction(context, WebRtcCallService.denyCallIntent(context), R.drawable.ic_close_grey600_32dp, R.string.NotificationBarManager__deny_call));
builder.addAction(getActivityNotificationAction(context, WebRtcCallActivity.ANSWER_ACTION, R.drawable.ic_phone_grey600_32dp, R.string.NotificationBarManager__answer_call));
if (callActivityRestricted()) {
@@ -63,10 +62,10 @@ public class CallNotificationBuilder {
}
} else if (type == TYPE_OUTGOING_RINGING) {
builder.setContentText(context.getString(R.string.NotificationBarManager__establishing_signal_call));
- builder.addAction(getServiceNotificationAction(context, WebRtcCallService.ACTION_LOCAL_HANGUP, R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__cancel_call));
+ builder.addAction(getServiceNotificationAction(context, WebRtcCallService.hangupIntent(context), R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__cancel_call));
} else {
builder.setContentText(context.getString(R.string.NotificationBarManager_signal_call_in_progress));
- builder.addAction(getServiceNotificationAction(context, WebRtcCallService.ACTION_LOCAL_HANGUP, R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__end_call));
+ builder.addAction(getServiceNotificationAction(context, WebRtcCallService.hangupIntent(context), R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__end_call));
}
return builder.build();
@@ -93,10 +92,7 @@ public class CallNotificationBuilder {
}
}
- private static NotificationCompat.Action getServiceNotificationAction(Context context, String action, int iconResId, int titleResId) {
- Intent intent = new Intent(context, WebRtcCallService.class);
- intent.setAction(action);
-
+ private static NotificationCompat.Action getServiceNotificationAction(Context context, Intent intent, int iconResId, int titleResId) {
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
return new NotificationCompat.Action(iconResId, context.getString(titleResId), pendingIntent);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/VoiceCallShare.java b/app/src/main/java/org/thoughtcrime/securesms/webrtc/VoiceCallShare.java
index 5f0b3d210f..6d05e712de 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/VoiceCallShare.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/VoiceCallShare.java
@@ -9,11 +9,9 @@ import android.text.TextUtils;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.WebRtcCallActivity;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.ringrtc.RemotePeer;
-import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
-import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
public class VoiceCallShare extends Activity {
@@ -34,11 +32,7 @@ public class VoiceCallShare extends Activity {
SimpleTask.run(() -> Recipient.external(this, destination), recipient -> {
if (!TextUtils.isEmpty(destination)) {
- Intent serviceIntent = new Intent(this, WebRtcCallService.class);
- serviceIntent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
- .putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(recipient.getId()))
- .putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.AUDIO_CALL.getCode());
- startService(serviceIntent);
+ ApplicationDependencies.getSignalCallManager().startOutgoingAudioCall(recipient);
Intent activityIntent = new Intent(this, WebRtcCallActivity.class);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);