From 9a93a8b28de305700238143829fbb2ff49fe8575 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Thu, 2 Feb 2017 18:34:51 -0800 Subject: [PATCH] Better support for building webrtc call view off of model Fixes #6144 // FREEBIE --- .../securesms/WebRtcCallActivity.java | 83 +++++--------- .../components/webrtc/PercentFrameLayout.java | 4 + .../components/webrtc/WebRtcCallControls.java | 4 + .../components/webrtc/WebRtcCallScreen.java | 48 +++++--- .../securesms/events/WebRtcCallEvent.java | 52 --------- .../securesms/events/WebRtcViewModel.java | 74 ++++++++++++ .../securesms/service/WebRtcCallService.java | 108 +++++++++++------- 7 files changed, 207 insertions(+), 166 deletions(-) delete mode 100644 src/org/thoughtcrime/securesms/events/WebRtcCallEvent.java create mode 100644 src/org/thoughtcrime/securesms/events/WebRtcViewModel.java diff --git a/src/org/thoughtcrime/securesms/WebRtcCallActivity.java b/src/org/thoughtcrime/securesms/WebRtcCallActivity.java index ae339cc0ae..ea9912ea68 100644 --- a/src/org/thoughtcrime/securesms/WebRtcCallActivity.java +++ b/src/org/thoughtcrime/securesms/WebRtcCallActivity.java @@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.components.webrtc.WebRtcCallScreen; import org.thoughtcrime.securesms.components.webrtc.WebRtcIncomingCallOverlay; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.events.WebRtcCallEvent; +import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.WebRtcCallService; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -66,6 +66,7 @@ public class WebRtcCallActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { + Log.w(TAG, "onCreate()"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); super.onCreate(savedInstanceState); @@ -80,6 +81,7 @@ public class WebRtcCallActivity extends Activity { @Override public void onResume() { + Log.w(TAG, "onResume()"); super.onResume(); initializeScreenshotSecurity(); @@ -89,6 +91,7 @@ public class WebRtcCallActivity extends Activity { @Override public void onNewIntent(Intent intent){ + Log.w(TAG, "onNewIntent"); if (ANSWER_ACTION.equals(intent.getAction())) { handleAnswerCall(); } else if (DENY_ACTION.equals(intent.getAction())) { @@ -100,6 +103,7 @@ public class WebRtcCallActivity extends Activity { @Override public void onPause() { + Log.w(TAG, "onPause"); super.onPause(); EventBus.getDefault().unregister(this); @@ -138,7 +142,7 @@ public class WebRtcCallActivity extends Activity { } private void handleSetMuteVideo(boolean muted) { - callScreen.setLocalVideoEnabled(!muted); +// callScreen.setLocalVideoEnabled(!muted); Intent intent = new Intent(this, WebRtcCallService.class); intent.setAction(WebRtcCallService.ACTION_SET_MUTE_VIDEO); @@ -147,7 +151,7 @@ public class WebRtcCallActivity extends Activity { } private void handleAnswerCall() { - WebRtcCallEvent event = EventBus.getDefault().getStickyEvent(WebRtcCallEvent.class); + WebRtcViewModel event = EventBus.getDefault().getStickyEvent(WebRtcViewModel.class); if (event != null) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_answering)); @@ -159,7 +163,7 @@ public class WebRtcCallActivity extends Activity { } private void handleDenyCall() { - WebRtcCallEvent event = EventBus.getDefault().getStickyEvent(WebRtcCallEvent.class); + WebRtcViewModel event = EventBus.getDefault().getStickyEvent(WebRtcViewModel.class); if (event != null) { Intent intent = new Intent(this, WebRtcCallService.class); @@ -177,18 +181,18 @@ public class WebRtcCallActivity extends Activity { intent.setAction(WebRtcCallService.ACTION_LOCAL_HANGUP); startService(intent); - WebRtcCallEvent event = EventBus.getDefault().getStickyEvent(WebRtcCallEvent.class); + WebRtcViewModel event = EventBus.getDefault().getStickyEvent(WebRtcViewModel.class); if (event != null) { WebRtcCallActivity.this.handleTerminate(event.getRecipient()); } } - private void handleIncomingCall(@NonNull WebRtcCallEvent event) { + private void handleIncomingCall(@NonNull WebRtcViewModel event) { callScreen.setIncomingCall(event.getRecipient()); } - private void handleOutgoingCall(@NonNull WebRtcCallEvent event) { + private void handleOutgoingCall(@NonNull WebRtcViewModel event) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_dialing)); } @@ -196,55 +200,37 @@ public class WebRtcCallActivity extends Activity { Log.w(TAG, "handleTerminate called"); callScreen.setActiveCall(recipient, getString(R.string.RedPhone_ending_call)); - EventBus.getDefault().removeStickyEvent(WebRtcCallEvent.class); + EventBus.getDefault().removeStickyEvent(WebRtcViewModel.class); delayedFinish(); } - private void handleCallRinging(@NonNull WebRtcCallEvent event) { + private void handleCallRinging(@NonNull WebRtcViewModel event) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_ringing)); } - private void handleCallBusy(@NonNull WebRtcCallEvent event) { + private void handleCallBusy(@NonNull WebRtcViewModel event) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_busy)); delayedFinish(BUSY_SIGNAL_DELAY_FINISH); } - private void handleCallConnected(@NonNull WebRtcCallEvent event) { + private void handleCallConnected(@NonNull WebRtcViewModel event) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES); callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_connected), ""); } - private void handleConnectingToInitiator(@NonNull WebRtcCallEvent event) { - callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_connecting)); - } - - private void handleHandshakeFailed(@NonNull WebRtcCallEvent event) { - callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_handshake_failed)); - delayedFinish(); - } - - private void handleRecipientUnavailable(@NonNull WebRtcCallEvent event) { + private void handleRecipientUnavailable(@NonNull WebRtcViewModel event) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_recipient_unavailable)); delayedFinish(); } - private void handlePerformingHandshake(@NonNull WebRtcCallEvent event) { - callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_performing_handshake)); - } - - private void handleServerFailure(@NonNull WebRtcCallEvent event) { + private void handleServerFailure(@NonNull WebRtcViewModel event) { callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_network_failed)); delayedFinish(); } - private void handleLoginFailed(@NonNull WebRtcCallEvent event) { - callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_login_failed)); - delayedFinish(); - } - - private void handleNoSuchUser(final @NonNull WebRtcCallEvent event) { + private void handleNoSuchUser(final @NonNull WebRtcViewModel event) { if (isFinishing()) return; // XXX Stuart added this check above, not sure why, so I'm repeating in ignorance. - moxie AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle(R.string.RedPhone_number_not_registered); @@ -266,16 +252,8 @@ public class WebRtcCallActivity extends Activity { dialog.show(); } - private void handleRemoteVideoDisabled(@NonNull WebRtcCallEvent event) { - callScreen.setRemoteVideoEnabled(false); - } - - private void handleRemoteVideoEnabled(@NonNull WebRtcCallEvent event) { - callScreen.setRemoteVideoEnabled(true); - } - - private void handleUntrustedIdentity(@NonNull WebRtcCallEvent event) { - final IdentityKey theirIdentity = (IdentityKey)event.getExtra(); + private void handleUntrustedIdentity(@NonNull WebRtcViewModel event) { + final IdentityKey theirIdentity = event.getIdentityKey(); final Recipient recipient = event.getRecipient(); callScreen.setUntrustedIdentity(recipient, theirIdentity); @@ -313,27 +291,24 @@ public class WebRtcCallActivity extends Activity { } @SuppressWarnings("unused") - public void onEventMainThread(final WebRtcCallEvent event) { - Log.w(TAG, "Got message from service: " + event.getType()); + public void onEventMainThread(final WebRtcViewModel event) { + Log.w(TAG, "Got message from service: " + event); - switch (event.getType()) { + switch (event.getState()) { case CALL_CONNECTED: handleCallConnected(event); break; - case SERVER_FAILURE: handleServerFailure(event); break; - case PERFORMING_HANDSHAKE: handlePerformingHandshake(event); break; - case HANDSHAKE_FAILED: handleHandshakeFailed(event); break; - case CONNECTING_TO_INITIATOR: handleConnectingToInitiator(event); break; + case NETWORK_FAILURE: handleServerFailure(event); break; case CALL_RINGING: handleCallRinging(event); break; case CALL_DISCONNECTED: handleTerminate(event.getRecipient()); break; case NO_SUCH_USER: handleNoSuchUser(event); break; case RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(event); break; - case INCOMING_CALL: handleIncomingCall(event); break; - case OUTGOING_CALL: handleOutgoingCall(event); break; + case CALL_INCOMING: handleIncomingCall(event); break; + case CALL_OUTGOING: handleOutgoingCall(event); break; case CALL_BUSY: handleCallBusy(event); break; - case LOGIN_FAILED: handleLoginFailed(event); break; - case REMOTE_VIDEO_DISABLED: handleRemoteVideoDisabled(event); break; - case REMOTE_VIDEO_ENABLED: handleRemoteVideoEnabled(event); break; case UNTRUSTED_IDENTITY: handleUntrustedIdentity(event); break; } + + callScreen.setLocalVideoEnabled(event.isLocalVideoEnabled()); + callScreen.setRemoteVideoEnabled(event.isRemoteVideoEnabled()); } private class HangupButtonListener implements WebRtcCallScreen.HangupButtonListener { diff --git a/src/org/thoughtcrime/securesms/components/webrtc/PercentFrameLayout.java b/src/org/thoughtcrime/securesms/components/webrtc/PercentFrameLayout.java index 81d048e402..9011d07b6a 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/PercentFrameLayout.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/PercentFrameLayout.java @@ -60,6 +60,10 @@ public class PercentFrameLayout extends ViewGroup { this.hidden = hidden; } + public boolean isHidden() { + return this.hidden; + } + public void setPosition(int xPercent, int yPercent, int widthPercent, int heightPercent) { this.xPercent = xPercent; this.yPercent = yPercent; diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java index 10dc2f7be9..dd17295a48 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java @@ -99,6 +99,10 @@ public class WebRtcCallControls extends LinearLayout { }); } + public boolean isVideoMuted() { + return !videoMuteButton.isChecked(); + } + public void setAudioButtonListener(final AudioButtonListener listener) { audioButton.setListener(listener); } diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java index f95ec6118f..a7fc55295f 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java @@ -180,23 +180,23 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient } public void setLocalVideoEnabled(boolean enabled) { - if (enabled) { + if (enabled && this.localRenderLayout.isHidden()) { this.localRenderLayout.setHidden(false); - } else { + this.localRenderLayout.requestLayout(); + } else if (!enabled && !this.localRenderLayout.isHidden()){ this.localRenderLayout.setHidden(true); + this.localRenderLayout.requestLayout(); } - - this.localRenderLayout.requestLayout(); } public void setRemoteVideoEnabled(boolean enabled) { - if (enabled) { + if (enabled && this.remoteRenderLayout.isHidden()) { this.remoteRenderLayout.setHidden(false); - } else { + this.remoteRenderLayout.requestLayout(); + } else if (!enabled && !this.remoteRenderLayout.isHidden()){ this.remoteRenderLayout.setHidden(true); + this.remoteRenderLayout.requestLayout(); } - - this.remoteRenderLayout.requestLayout(); } private void initialize() { @@ -226,21 +226,31 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient private void setConnected(SurfaceViewRenderer localRenderer, SurfaceViewRenderer remoteRenderer) { - localRenderLayout.setPosition(7, 7, 25, 25); - localRenderLayout.setSquare(true); - remoteRenderLayout.setPosition(0, 0, 100, 100); + if (localRenderLayout.getChildCount() == 0 && remoteRenderLayout.getChildCount() == 0) { + if (localRenderer.getParent() != null) { + ((ViewGroup)localRenderer.getParent()).removeView(localRenderer); + } - localRenderer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); + if (remoteRenderer.getParent() != null) { + ((ViewGroup)remoteRenderer.getParent()).removeView(remoteRenderer); + } - remoteRenderer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); + localRenderLayout.setPosition(7, 7, 25, 25); + localRenderLayout.setSquare(true); + remoteRenderLayout.setPosition(0, 0, 100, 100); - localRenderer.setMirror(true); - localRenderer.setZOrderMediaOverlay(true); + localRenderer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); - localRenderLayout.addView(localRenderer); - remoteRenderLayout.addView(remoteRenderer); + remoteRenderer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + + localRenderer.setMirror(true); + localRenderer.setZOrderMediaOverlay(true); + + localRenderLayout.addView(localRenderer); + remoteRenderLayout.addView(remoteRenderer); + } } private void setPersonInfo(final @NonNull Recipient recipient) { diff --git a/src/org/thoughtcrime/securesms/events/WebRtcCallEvent.java b/src/org/thoughtcrime/securesms/events/WebRtcCallEvent.java deleted file mode 100644 index bb68cc707d..0000000000 --- a/src/org/thoughtcrime/securesms/events/WebRtcCallEvent.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.thoughtcrime.securesms.events; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import org.thoughtcrime.securesms.recipients.Recipient; - -public class WebRtcCallEvent { - - public enum Type { - CALL_CONNECTED, - WAITING_FOR_RESPONDER, - SERVER_FAILURE, - PERFORMING_HANDSHAKE, - HANDSHAKE_FAILED, - CONNECTING_TO_INITIATOR, - CALL_DISCONNECTED, - CALL_RINGING, - RECIPIENT_UNAVAILABLE, - INCOMING_CALL, - OUTGOING_CALL, - CALL_BUSY, - LOGIN_FAILED, - DEBUG_INFO, - NO_SUCH_USER, - REMOTE_VIDEO_ENABLED, - REMOTE_VIDEO_DISABLED, - UNTRUSTED_IDENTITY - } - - private final @NonNull Type type; - private final @NonNull Recipient recipient; - private final @Nullable Object extra; - - public WebRtcCallEvent(@NonNull Type type, @NonNull Recipient recipient, @Nullable Object extra) { - this.type = type; - this.recipient = recipient; - this.extra = extra; - } - - public @NonNull Type getType() { - return type; - } - - public @NonNull Recipient getRecipient() { - return recipient; - } - - public @Nullable Object getExtra() { - return extra; - } -} diff --git a/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java b/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java new file mode 100644 index 0000000000..a62377d5d6 --- /dev/null +++ b/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java @@ -0,0 +1,74 @@ +package org.thoughtcrime.securesms.events; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.thoughtcrime.securesms.recipients.Recipient; +import org.whispersystems.libsignal.IdentityKey; + +public class WebRtcViewModel { + + public enum State { + // Normal states + CALL_INCOMING, + CALL_OUTGOING, + CALL_CONNECTED, + CALL_RINGING, + CALL_BUSY, + CALL_DISCONNECTED, + + // Error states + NETWORK_FAILURE, + RECIPIENT_UNAVAILABLE, + NO_SUCH_USER, + UNTRUSTED_IDENTITY, + } + + + private final @NonNull State state; + private final @NonNull Recipient recipient; + private final @Nullable IdentityKey identityKey; + + private final boolean remoteVideoEnabled; + private final boolean localVideoEnabled; + + public WebRtcViewModel(@NonNull State state, @NonNull Recipient recipient, boolean localVideoEnabled, boolean remoteVideoEnabled) { + this(state, recipient, null, localVideoEnabled, remoteVideoEnabled); + } + + public WebRtcViewModel(@NonNull State state, @NonNull Recipient recipient, + @Nullable IdentityKey identityKey, + boolean localVideoEnabled, boolean remoteVideoEnabled) + { + this.state = state; + this.recipient = recipient; + this.identityKey = identityKey; + this.localVideoEnabled = localVideoEnabled; + this.remoteVideoEnabled = remoteVideoEnabled; + } + + public @NonNull State getState() { + return state; + } + + public @NonNull Recipient getRecipient() { + return recipient; + } + + @Nullable + public IdentityKey getIdentityKey() { + return identityKey; + } + + public boolean isRemoteVideoEnabled() { + return remoteVideoEnabled; + } + + public boolean isLocalVideoEnabled() { + return localVideoEnabled; + } + + public String toString() { + return "[State: " + state + ", recipient: " + recipient.getNumber() + ", identity: " + identityKey + ", remoteVideo: " + remoteVideoEnabled + ", localVideo: " + localVideoEnabled + "]"; + } +} diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java index 62d8112132..40bdbcead0 100644 --- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -27,7 +27,7 @@ import org.thoughtcrime.securesms.WebRtcCallActivity; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory; -import org.thoughtcrime.securesms.events.WebRtcCallEvent; +import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; @@ -57,6 +57,7 @@ import org.webrtc.SessionDescription; import org.webrtc.SurfaceViewRenderer; import org.webrtc.VideoRenderer; import org.webrtc.VideoTrack; +import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -68,8 +69,8 @@ import org.whispersystems.signalservice.api.messages.calls.OfferMessage; import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.api.util.InvalidNumberException; -import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; import java.io.IOException; import java.nio.ByteBuffer; @@ -111,8 +112,8 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt public static final String EXTRA_ICE_SDP_MID = "ice_sdp_mid"; public static final String EXTRA_ICE_SDP_LINE_INDEX = "ice_sdp_line_index"; - public static final String ACTION_INCOMING_CALL = "INCOMING_CALL"; - public static final String ACTION_OUTGOING_CALL = "OUTGOING_CALL"; + public static final String ACTION_INCOMING_CALL = "CALL_INCOMING"; + public static final String ACTION_OUTGOING_CALL = "CALL_OUTGOING"; public static final String ACTION_ANSWER_CALL = "ANSWER_CALL"; public static final String ACTION_DENY_CALL = "DENY_CALL"; public static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP"; @@ -129,10 +130,11 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt public static final String ACTION_REMOTE_VIDEO_MUTE = "REMOTE_VIDEO_MUTE"; public static final String ACTION_ICE_CONNECTED = "ICE_CONNECTED"; - private CallState callState = CallState.STATE_IDLE; - private boolean audioEnabled = true; - private boolean videoEnabled = false; - private Handler serviceHandler = new Handler(); + private CallState callState = CallState.STATE_IDLE; + private boolean audioEnabled = true; + private boolean localVideoEnabled = false; + private boolean remoteVideoEnabled = false; + private Handler serviceHandler = new Handler(); @Inject public SignalMessageSenderFactory messageSenderFactory; @Inject public SignalServiceAccountManager accountManager; @@ -289,7 +291,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt initializeVideo(); - sendMessage(WebRtcCallEvent.Type.OUTGOING_CALL, recipient, null); + sendMessage(WebRtcViewModel.State.CALL_OUTGOING, recipient, localVideoEnabled, remoteVideoEnabled); lockManager.updatePhoneState(LockManager.PhoneState.IN_CALL); outgoingRinger.playSonar(); @@ -317,10 +319,13 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt @Override public void onFailureContinue(Throwable error) { Log.w(TAG, error); - if (error instanceof IOException) { - sendMessage(WebRtcCallEvent.Type.SERVER_FAILURE, recipient, null); - } else if (error instanceof UntrustedIdentityException) { - sendMessage(WebRtcCallEvent.Type.UNTRUSTED_IDENTITY, recipient, ((UntrustedIdentityException)error).getIdentityKey()); + + if (error instanceof UntrustedIdentityException) { + sendMessage(WebRtcViewModel.State.UNTRUSTED_IDENTITY, recipient, ((UntrustedIdentityException)error).getIdentityKey(), localVideoEnabled, remoteVideoEnabled); + } else if (error instanceof UnregisteredUserException) { + sendMessage(WebRtcViewModel.State.NO_SUCH_USER, recipient, localVideoEnabled, remoteVideoEnabled); + } else if (error instanceof IOException) { + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localVideoEnabled, remoteVideoEnabled); } terminate(); @@ -357,7 +362,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt @Override public void onFailureContinue(Throwable error) { Log.w(TAG, error); - sendMessage(WebRtcCallEvent.Type.SERVER_FAILURE, recipient, null); + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localVideoEnabled, remoteVideoEnabled); terminate(); } @@ -406,7 +411,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt @Override public void onFailureContinue(Throwable error) { Log.w(TAG, error); - sendMessage(WebRtcCallEvent.Type.SERVER_FAILURE, recipient, null); + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localVideoEnabled, remoteVideoEnabled); terminate(); } @@ -420,7 +425,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt this.callState = CallState.STATE_LOCAL_RINGING; this.lockManager.updatePhoneState(LockManager.PhoneState.INTERACTIVE); - sendMessage(WebRtcCallEvent.Type.INCOMING_CALL, recipient, null); + sendMessage(WebRtcViewModel.State.CALL_INCOMING, recipient, localVideoEnabled, remoteVideoEnabled); startCallCardActivity(); incomingRinger.start(); CallNotificationManager.setCallInProgress(this, TYPE_INCOMING_RINGING, recipient); @@ -430,7 +435,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt this.callState = CallState.STATE_REMOTE_RINGING; this.outgoingRinger.playRing(); - sendMessage(WebRtcCallEvent.Type.CALL_RINGING, recipient, null); + sendMessage(WebRtcViewModel.State.CALL_RINGING, recipient, localVideoEnabled, remoteVideoEnabled); } } @@ -455,17 +460,17 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt outgoingRinger.playComplete(); lockManager.updatePhoneState(LockManager.PhoneState.IN_CALL); - sendMessage(WebRtcCallEvent.Type.CALL_CONNECTED, recipient, "un used"); + sendMessage(WebRtcViewModel.State.CALL_CONNECTED, recipient, localVideoEnabled, remoteVideoEnabled); CallNotificationManager.setCallInProgress(this, TYPE_ESTABLISHED, recipient); this.peerConnection.setAudioEnabled(audioEnabled); - this.peerConnection.setVideoEnabled(videoEnabled); + this.peerConnection.setVideoEnabled(localVideoEnabled); this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder() .setVideoStreamingStatus(WebRtcDataProtos.VideoStreamingStatus.newBuilder() .setId(this.callId) - .setEnabled(videoEnabled)) + .setEnabled(localVideoEnabled)) .build().toByteArray()), false)); } @@ -488,7 +493,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt return; } - sendMessage(WebRtcCallEvent.Type.CALL_BUSY, recipient, null); + sendMessage(WebRtcViewModel.State.CALL_BUSY, recipient, localVideoEnabled, remoteVideoEnabled); outgoingRinger.playBusy(); serviceHandler.postDelayed(new Runnable() { @@ -505,7 +510,7 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt this.callState != CallState.STATE_CONNECTED) { Log.w(TAG, "Timing out call: " + this.callId); - sendMessage(WebRtcCallEvent.Type.CALL_DISCONNECTED, this.recipient, null); + sendMessage(WebRtcViewModel.State.CALL_DISCONNECTED, this.recipient, localVideoEnabled, remoteVideoEnabled); terminate(); } } @@ -580,9 +585,9 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt } if (this.callState == CallState.STATE_DIALING || this.callState == CallState.STATE_REMOTE_RINGING) { - sendMessage(WebRtcCallEvent.Type.RECIPIENT_UNAVAILABLE, this.recipient, null); + sendMessage(WebRtcViewModel.State.RECIPIENT_UNAVAILABLE, this.recipient, localVideoEnabled, remoteVideoEnabled); } else { - sendMessage(WebRtcCallEvent.Type.CALL_DISCONNECTED, this.recipient, null); + sendMessage(WebRtcViewModel.State.CALL_DISCONNECTED, this.recipient, localVideoEnabled, remoteVideoEnabled); } if (this.callState == CallState.STATE_ANSWERING || this.callState == CallState.STATE_LOCAL_RINGING) { @@ -603,19 +608,21 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt private void handleSetMuteVideo(Intent intent) { boolean muted = intent.getBooleanExtra(EXTRA_MUTE, false); - this.videoEnabled = !muted; + this.localVideoEnabled = !muted; if (this.peerConnection != null) { - this.peerConnection.setVideoEnabled(this.videoEnabled); + this.peerConnection.setVideoEnabled(this.localVideoEnabled); } if (this.callId != null && this.dataChannel != null) { this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder() .setVideoStreamingStatus(WebRtcDataProtos.VideoStreamingStatus.newBuilder() .setId(this.callId) - .setEnabled(videoEnabled)) + .setEnabled(localVideoEnabled)) .build().toByteArray()), false)); } + + sendMessage(viewModelStateFor(callState), this.recipient, localVideoEnabled, remoteVideoEnabled); } private void handleRemoteVideoMute(Intent intent) { @@ -627,11 +634,8 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt return; } - if (muted) { - sendMessage(WebRtcCallEvent.Type.REMOTE_VIDEO_DISABLED, this.recipient, null); - } else { - sendMessage(WebRtcCallEvent.Type.REMOTE_VIDEO_ENABLED, this.recipient, null); - } + this.remoteVideoEnabled = !muted; + sendMessage(WebRtcViewModel.State.CALL_CONNECTED, this.recipient, localVideoEnabled, remoteVideoEnabled); } /// Helper Methods @@ -709,21 +713,30 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt shutdownAudio(); - this.callState = CallState.STATE_IDLE; - this.recipient = null; - this.callId = null; - this.audioEnabled = true; - this.videoEnabled = false; - this.pendingIceUpdates = null; + this.callState = CallState.STATE_IDLE; + this.recipient = null; + this.callId = null; + this.audioEnabled = true; + this.localVideoEnabled = false; + this.remoteVideoEnabled = false; + this.pendingIceUpdates = null; lockManager.updatePhoneState(LockManager.PhoneState.IDLE); } - private void sendMessage(@NonNull WebRtcCallEvent.Type type, + private void sendMessage(@NonNull WebRtcViewModel.State state, @NonNull Recipient recipient, - @Nullable Object extra) + boolean localVideoEnabled, boolean remoteVideoEnabled) { - EventBus.getDefault().postSticky(new WebRtcCallEvent(type, recipient, extra)); + EventBus.getDefault().postSticky(new WebRtcViewModel(state, recipient, localVideoEnabled, remoteVideoEnabled)); + } + + private void sendMessage(@NonNull WebRtcViewModel.State state, + @NonNull Recipient recipient, + @NonNull IdentityKey identityKey, + boolean localVideoEnabled, boolean remoteVideoEnabled) + { + EventBus.getDefault().postSticky(new WebRtcViewModel(state, recipient, identityKey, localVideoEnabled, remoteVideoEnabled)); } private ListenableFutureTask sendMessage(@NonNull final Recipient recipient, @@ -952,6 +965,19 @@ public class WebRtcCallService extends Service implements InjectableType, CallSt return futureTask; } + private WebRtcViewModel.State viewModelStateFor(CallState state) { + switch (state) { + case STATE_CONNECTED: return WebRtcViewModel.State.CALL_CONNECTED; + case STATE_DIALING: return WebRtcViewModel.State.CALL_OUTGOING; + case STATE_REMOTE_RINGING: return WebRtcViewModel.State.CALL_RINGING; + case STATE_LOCAL_RINGING: return WebRtcViewModel.State.CALL_INCOMING; + case STATE_ANSWERING: return WebRtcViewModel.State.CALL_INCOMING; + case STATE_IDLE: return WebRtcViewModel.State.CALL_DISCONNECTED; + } + + return WebRtcViewModel.State.CALL_DISCONNECTED; + } + private class TimeoutRunnable implements Runnable { private final long callId;