display status information in ui

Daniel Gultsch created

Change summary

src/main/AndroidManifest.xml                                              |  1 
src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java           | 35 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java | 11 
src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java     |  1 
src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java       | 32 
src/main/res/layout/activity_rtp_session.xml                              | 21 
src/main/res/values/strings.xml                                           |  1 
7 files changed, 84 insertions(+), 18 deletions(-)

Detailed changes

src/main/AndroidManifest.xml 🔗

@@ -32,6 +32,7 @@
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
 
     <uses-permission
         android:name="android.permission.READ_PHONE_STATE"

src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java 🔗

@@ -37,8 +37,13 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
                         | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
-        this.binding.acceptCall.setOnClickListener(this::acceptCall);
         this.binding.rejectCall.setOnClickListener(this::rejectCall);
+        this.binding.endCall.setOnClickListener(this::endCall);
+        this.binding.acceptCall.setOnClickListener(this::acceptCall);
+    }
+
+    private void endCall(View view) {
+        requireRtpConnection().endCall();
     }
 
     private void rejectCall(View view) {
@@ -70,11 +75,13 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
             }
             this.rtpConnectionReference = reference;
             binding.with.setText(getWith().getDisplayName());
-            showState(requireRtpConnection().getEndUserState());
+            final RtpEndUserState currentState = requireRtpConnection().getEndUserState();
+            updateStateDisplay(currentState);
+            updateButtonConfiguration(currentState);
         }
     }
 
-    private void showState(final RtpEndUserState state) {
+    private void updateStateDisplay(final RtpEndUserState state) {
         switch (state) {
             case INCOMING_CALL:
                 binding.status.setText(R.string.rtp_state_incoming_call);
@@ -88,6 +95,25 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
             case ACCEPTING_CALL:
                 binding.status.setText(R.string.rtp_state_accepting_call);
                 break;
+            case ENDING_CALL:
+                binding.status.setText(R.string.rtp_state_ending_call);
+                break;
+        }
+    }
+
+    private void updateButtonConfiguration(final RtpEndUserState state) {
+        if (state == RtpEndUserState.INCOMING_CALL) {
+            this.binding.rejectCall.show();
+            this.binding.endCall.hide();
+            this.binding.acceptCall.show();
+        } else if (state == RtpEndUserState.ENDING_CALL) {
+            this.binding.rejectCall.hide();
+            this.binding.endCall.hide();
+            this.binding.acceptCall.hide();
+        } else {
+            this.binding.rejectCall.hide();
+            this.binding.endCall.show();
+            this.binding.acceptCall.hide();
         }
     }
 
@@ -110,7 +136,8 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
         final AbstractJingleConnection.Id id = requireRtpConnection().getId();
         if (account == id.account && id.with.equals(with)) {
             runOnUiThread(()->{
-                showState(state);
+                updateStateDisplay(state);
+                updateButtonConfiguration(state);
             });
         } else {
             Log.d(Config.LOGTAG,"received update for other rtp session");

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java 🔗

@@ -317,6 +317,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
                     return RtpEndUserState.CONNECTED;
                 } else if (state == PeerConnection.PeerConnectionState.NEW || state == PeerConnection.PeerConnectionState.CONNECTING) {
                     return RtpEndUserState.CONNECTING;
+                } else if (state == PeerConnection.PeerConnectionState.CLOSED) {
+                    return RtpEndUserState.ENDING_CALL;
                 } else {
                     return RtpEndUserState.FAILED;
                 }
@@ -342,6 +344,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
         Log.d(Config.LOGTAG, "todo rejecting call");
     }
 
+    public void endCall() {
+        if (isInState(State.SESSION_INITIALIZED, State.SESSION_ACCEPTED)) {
+            webRTCWrapper.close();
+        } else {
+            Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": called 'endCall' while in state " + this.state);
+        }
+    }
+
     private void setupWebRTC() {
         this.webRTCWrapper.setup(this.xmppConnectionService);
         this.webRTCWrapper.initializePeerConnection();
@@ -392,6 +402,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 
     @Override
     public void onConnectionChange(PeerConnection.PeerConnectionState newState) {
+        Log.d(Config.LOGTAG,id.account.getJid().asBareJid()+": PeerConnectionState changed to "+newState);
         updateEndUserState();
     }
 

src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java 🔗

@@ -8,5 +8,6 @@ public enum RtpEndUserState {
     RINGING, //'propose' has been sent out and it has been 184 acked
     ACCEPTED_ON_OTHER_DEVICE, //received 'accept' from one of our own devices
     ACCEPTING_CALL, //'proceed' message has been sent; but no session-initiate has been received
+    ENDING_CALL, //libwebrt says 'closed' but session-terminate hasnt gone through
     FAILED //something went wrong. TODO needs more concrete error states
 }

src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java 🔗

@@ -81,8 +81,8 @@ public class WebRTCWrapper {
         @Override
         public void onAddStream(MediaStream mediaStream) {
             Log.d(Config.LOGTAG, "onAddStream");
-            for(AudioTrack audioTrack : mediaStream.audioTracks) {
-                Log.d(Config.LOGTAG,"remote? - audioTrack enabled:"+audioTrack.enabled()+" state="+audioTrack.state());
+            for (AudioTrack audioTrack : mediaStream.audioTracks) {
+                Log.d(Config.LOGTAG, "remote? - audioTrack enabled:" + audioTrack.enabled() + " state=" + audioTrack.state());
             }
             final List<VideoTrack> videoTracks = mediaStream.videoTracks;
             if (videoTracks.size() > 0) {
@@ -130,8 +130,8 @@ public class WebRTCWrapper {
 
         CameraVideoCapturer capturer = null;
         Camera1Enumerator camera1Enumerator = new Camera1Enumerator();
-        for(String deviceName : camera1Enumerator.getDeviceNames()) {
-            Log.d(Config.LOGTAG,"camera device name: "+deviceName);
+        for (String deviceName : camera1Enumerator.getDeviceNames()) {
+            Log.d(Config.LOGTAG, "camera device name: " + deviceName);
             if (camera1Enumerator.isFrontFacing(deviceName)) {
                 capturer = camera1Enumerator.createCapturer(deviceName, new CameraVideoCapturer.CameraEventsHandler() {
                     @Override
@@ -151,12 +151,12 @@ public class WebRTCWrapper {
 
                     @Override
                     public void onCameraOpening(String s) {
-                        Log.d(Config.LOGTAG,"onCameraOpening");
+                        Log.d(Config.LOGTAG, "onCameraOpening");
                     }
 
                     @Override
                     public void onFirstFrameAvailable() {
-                        Log.d(Config.LOGTAG,"onFirstFrameAvailable");
+                        Log.d(Config.LOGTAG, "onFirstFrameAvailable");
                     }
 
                     @Override
@@ -179,7 +179,7 @@ public class WebRTCWrapper {
         final AudioSource audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
 
         final AudioTrack audioTrack = peerConnectionFactory.createAudioTrack("my-audio-track", audioSource);
-        Log.d(Config.LOGTAG,"audioTrack enabled:"+audioTrack.enabled()+" state="+audioTrack.state());
+        Log.d(Config.LOGTAG, "audioTrack enabled:" + audioTrack.enabled() + " state=" + audioTrack.state());
         final MediaStream stream = peerConnectionFactory.createLocalMediaStream("my-media-stream");
         stream.addTrack(audioTrack);
         //stream.addTrack(videoTrack);
@@ -200,6 +200,9 @@ public class WebRTCWrapper {
         this.peerConnection = peerConnection;
     }
 
+    public void close() {
+        requirePeerConnection().close();
+    }
 
 
     public ListenableFuture<SessionDescription> createOffer() {
@@ -287,15 +290,19 @@ public class WebRTCWrapper {
     }
 
     public void addIceCandidate(IceCandidate iceCandidate) {
+        requirePeerConnection().addIceCandidate(iceCandidate);
+    }
+
+    public PeerConnection.PeerConnectionState getState() {
+        return requirePeerConnection().connectionState();
+    }
+
+    private PeerConnection requirePeerConnection() {
         final PeerConnection peerConnection = this.peerConnection;
         if (peerConnection == null) {
             throw new IllegalStateException("initialize PeerConnection first");
         }
-        peerConnection.addIceCandidate(iceCandidate);
-    }
-
-    public PeerConnection.PeerConnectionState getState() {
-        return this.peerConnection.connectionState();
+        return peerConnection;
     }
 
     private static abstract class SetSdpObserver implements SdpObserver {
@@ -329,6 +336,7 @@ public class WebRTCWrapper {
 
     public interface EventCallback {
         void onIceCandidate(IceCandidate iceCandidate);
+
         void onConnectionChange(PeerConnection.PeerConnectionState newState);
     }
 }

src/main/res/layout/activity_rtp_session.xml 🔗

@@ -54,7 +54,22 @@
                 app:backgroundTint="@color/red700"
                 app:elevation="4dp"
                 app:fabCustomSize="72dp"
-                app:maxImageSize="36dp" />
+                app:maxImageSize="36dp"
+                android:visibility="gone"
+                tools:visibility="visible"/>
+
+            <android.support.design.widget.FloatingActionButton
+                android:id="@+id/end_call"
+                android:layout_width="wrap_content"
+                android:layout_margin="16dp"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true"
+                android:src="@drawable/ic_call_end_white_48dp"
+                app:backgroundTint="@color/red700"
+                app:elevation="4dp"
+                app:fabCustomSize="72dp"
+                app:maxImageSize="36dp"
+                android:visibility="gone"/>
 
             <android.support.design.widget.FloatingActionButton
                 android:id="@+id/accept_call"
@@ -68,7 +83,9 @@
                 app:backgroundTint="@color/green700"
                 app:elevation="4dp"
                 app:fabCustomSize="72dp"
-                app:maxImageSize="36dp" />
+                app:maxImageSize="36dp"
+                android:visibility="gone"
+                tools:visibility="visible"/>
         </RelativeLayout>
 
     </RelativeLayout>

src/main/res/values/strings.xml 🔗

@@ -889,6 +889,7 @@
     <string name="rtp_state_connecting">Connecting</string>
     <string name="rtp_state_connected">Connected</string>
     <string name="rtp_state_accepting_call">Accepting call</string>
+    <string name="rtp_state_ending_call">Ending call</string>
     <plurals name="view_users">
         <item quantity="one">View %1$d Participant</item>
         <item quantity="other">View %1$d Participants</item>