From f8c032841612baf4b85f06c76c71b7d9838b7613 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 7 Apr 2020 11:36:28 +0200 Subject: [PATCH] dummy Jingle activity --- src/main/AndroidManifest.xml | 2 + .../generator/MessageGenerator.java | 5 +- .../conversations/parser/MessageParser.java | 29 +++++-- .../conversations/ui/RtpSessionActivity.java | 46 +++++++++++ .../xmpp/jingle/AbstractJingleConnection.java | 2 + .../xmpp/jingle/JingleConnectionManager.java | 27 ++++++- .../xmpp/jingle/JingleRtpConnection.java | 14 +++- .../xmpp/jingle/WebRTCWrapper.java | 68 +++++++++++++++- .../drawable-hdpi/ic_call_end_white_48dp.png | Bin 0 -> 553 bytes .../res/drawable-hdpi/ic_call_white_48dp.png | Bin 0 -> 597 bytes .../drawable-mdpi/ic_call_end_white_48dp.png | Bin 0 -> 389 bytes .../res/drawable-mdpi/ic_call_white_48dp.png | Bin 0 -> 420 bytes .../drawable-xhdpi/ic_call_end_white_48dp.png | Bin 0 -> 712 bytes .../res/drawable-xhdpi/ic_call_white_48dp.png | Bin 0 -> 778 bytes .../ic_call_end_white_48dp.png | Bin 0 -> 1039 bytes .../drawable-xxhdpi/ic_call_white_48dp.png | Bin 0 -> 1134 bytes .../ic_call_end_white_48dp.png | Bin 0 -> 1355 bytes .../drawable-xxxhdpi/ic_call_white_48dp.png | Bin 0 -> 1529 bytes src/main/res/layout/activity_rtp_session.xml | 75 ++++++++++++++++++ src/main/res/values/colors.xml | 1 + src/main/res/values/styles.xml | 7 +- src/main/res/values/themes.xml | 1 + 22 files changed, 263 insertions(+), 14 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java create mode 100644 src/main/res/drawable-hdpi/ic_call_end_white_48dp.png create mode 100644 src/main/res/drawable-hdpi/ic_call_white_48dp.png create mode 100644 src/main/res/drawable-mdpi/ic_call_end_white_48dp.png create mode 100644 src/main/res/drawable-mdpi/ic_call_white_48dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_call_end_white_48dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_call_white_48dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_call_end_white_48dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_call_white_48dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_call_end_white_48dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_call_white_48dp.png create mode 100644 src/main/res/layout/activity_rtp_session.xml diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 5516758fa..b1ac0dc4e 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ + @@ -286,6 +287,7 @@ + diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 423ed9f91..393cec5d4 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -19,6 +19,7 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; +import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import rocks.xmpp.addr.Jid; @@ -233,12 +234,14 @@ public class MessageGenerator extends AbstractGenerator { return packet; } - public MessagePacket sessionProposal(JingleConnectionManager.RtpSessionProposal proposal) { + public MessagePacket sessionProposal(final JingleConnectionManager.RtpSessionProposal proposal) { final MessagePacket packet = new MessagePacket(); packet.setTo(proposal.with); + packet.setId(JingleRtpConnection.JINGLE_MESSAGE_ID_PREFIX+proposal.sessionId); final Element propose = packet.addChild("propose", Namespace.JINGLE_MESSAGE); propose.setAttribute("id", proposal.sessionId); propose.addChild("description", Namespace.JINGLE_APPS_RTP); + packet.addChild("request", "urn:xmpp:receipts"); return packet; } } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index a53613e28..4b15b8b72 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -43,6 +43,8 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.OnMessagePacketReceived; import eu.siacs.conversations.xmpp.chatstate.ChatState; +import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; +import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import rocks.xmpp.addr.Jid; @@ -301,11 +303,18 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece private boolean handleErrorMessage(Account account, MessagePacket packet) { if (packet.getType() == MessagePacket.TYPE_ERROR) { - Jid from = packet.getFrom(); - if (from != null) { + final Jid from = packet.getFrom(); + final String id = packet.getId(); + if (from != null && id != null) { + if (id.startsWith(JingleRtpConnection.JINGLE_MESSAGE_ID_PREFIX)) { + final String sessionId = id.substring(JingleRtpConnection.JINGLE_MESSAGE_ID_PREFIX.length()); + mXmppConnectionService.getJingleConnectionManager() + .updateProposedSessionDiscovered(account, from, sessionId, JingleConnectionManager.DeviceDiscoveryState.FAILED); + return true; + } mXmppConnectionService.markMessage(account, from.asBareJid(), - packet.getId(), + id, Message.STATUS_SEND_FAILED, extractErrorMessage(packet)); final Element error = packet.findChild("error"); @@ -815,7 +824,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (!isTypeGroupChat) { for (Element child : packet.getChildren()) { if (Namespace.JINGLE_MESSAGE.equals(child.getNamespace()) && JINGLE_MESSAGE_ELEMENT_NAMES.contains(child.getName())) { + if (!account.getJid().asBareJid().equals(from.asBareJid())) { + processMessageReceipts(account, packet, query); + } mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child); + break; } } } @@ -831,8 +844,14 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (query != null && id != null && packet.getTo() != null) { query.removePendingReceiptRequest(new ReceiptRequest(packet.getTo(), id)); } - } else { - mXmppConnectionService.markMessage(account, from.asBareJid(), received.getAttribute("id"), Message.STATUS_SEND_RECEIVED); + } else if (id != null) { + if (id.startsWith(JingleRtpConnection.JINGLE_MESSAGE_ID_PREFIX)) { + final String sessionId = id.substring(JingleRtpConnection.JINGLE_MESSAGE_ID_PREFIX.length()); + mXmppConnectionService.getJingleConnectionManager() + .updateProposedSessionDiscovered(account, from, sessionId, JingleConnectionManager.DeviceDiscoveryState.DISCOVERED); + } else { + mXmppConnectionService.markMessage(account, from.asBareJid(), id, Message.STATUS_SEND_RECEIVED); + } } } Element displayed = packet.findChild("displayed", "urn:xmpp:chat-markers:0"); diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java new file mode 100644 index 000000000..2fdf2ac65 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -0,0 +1,46 @@ +package eu.siacs.conversations.ui; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityRtpSessionBinding; + +public class RtpSessionActivity extends XmppActivity { + + public static final String EXTRA_WITH = "with"; + + private ActivityRtpSessionBinding binding; + + public void onCreate(Bundle savedInstanceState) { + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | 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); + } + + private void rejectCall(View view) { + + } + + private void acceptCall(View view) { + + } + + @Override + protected void refreshUiReal() { + + } + + @Override + void onBackendConnected() { + + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java index 65fce4205..603371394 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java @@ -11,6 +11,8 @@ import rocks.xmpp.addr.Jid; public abstract class AbstractJingleConnection { + public static final String JINGLE_MESSAGE_ID_PREFIX = "jm-propose-"; + protected final JingleConnectionManager jingleConnectionManager; protected final XmppConnectionService xmppConnectionService; protected final Id id; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 146892e82..bc9e25f2e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -30,7 +30,7 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import rocks.xmpp.addr.Jid; public class JingleConnectionManager extends AbstractConnectionManager { - private final Set rtpSessionProposals = new HashSet<>(); + private final HashMap rtpSessionProposals = new HashMap<>(); private final Map connections = new ConcurrentHashMap<>(); private HashMap primaryCandidates = new HashMap<>(); @@ -108,7 +108,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { } final RtpSessionProposal proposal = new RtpSessionProposal(account, with.asBareJid(), sessionId); synchronized (rtpSessionProposals) { - if (rtpSessionProposals.remove(proposal)) { + if (rtpSessionProposals.remove(proposal) != null) { final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, account.getJid()); this.connections.put(id, rtpConnection); rtpConnection.transitionOrThrow(AbstractJingleConnection.State.PROPOSED); @@ -190,7 +190,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { public void proposeJingleRtpSession(final Account account, final Contact contact) { final RtpSessionProposal proposal = RtpSessionProposal.of(account, contact.getJid().asBareJid()); synchronized (this.rtpSessionProposals) { - this.rtpSessionProposals.add(proposal); + this.rtpSessionProposals.put(proposal, DeviceDiscoveryState.SEARCHING); final MessagePacket messagePacket = mXmppConnectionService.getMessageGenerator().sessionProposal(proposal); Log.d(Config.LOGTAG,messagePacket.toString()); mXmppConnectionService.sendMessagePacket(account, messagePacket); @@ -244,6 +244,23 @@ public class JingleConnectionManager extends AbstractConnectionManager { } } + public void updateProposedSessionDiscovered(Account account, Jid from, String sessionId, final DeviceDiscoveryState target) { + final RtpSessionProposal sessionProposal = new RtpSessionProposal(account,from.asBareJid(),sessionId); + synchronized (this.rtpSessionProposals) { + final DeviceDiscoveryState currentState = rtpSessionProposals.get(sessionProposal); + if (currentState == null) { + Log.d(Config.LOGTAG,"unable to find session proposal for session id "+sessionId); + return; + } + if (currentState == DeviceDiscoveryState.DISCOVERED) { + Log.d(Config.LOGTAG,"session proposal already at discovered. not going to fall back"); + return; + } + this.rtpSessionProposals.put(sessionProposal, target); + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": flagging session "+sessionId+" as "+target); + } + } + public static class RtpSessionProposal { private final Account account; public final Jid with; @@ -274,4 +291,8 @@ public class JingleConnectionManager extends AbstractConnectionManager { return Objects.hashCode(account.getJid(), with, sessionId); } } + + public enum DeviceDiscoveryState { + SEARCHING, DISCOVERED, FAILED + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 3e9759c22..f18212df8 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.xmpp.jingle; +import android.content.Intent; import android.util.Log; import com.google.common.collect.ImmutableList; @@ -15,6 +16,7 @@ import java.util.List; import java.util.Map; import eu.siacs.conversations.Config; +import eu.siacs.conversations.ui.RtpSessionActivity; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.jingle.stanzas.Group; @@ -217,13 +219,21 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (originatedFromMyself) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": saw proposal from mysql. ignoring"); } else if (transition(State.PROPOSED)) { - //TODO start ringing or something - pickUpCall(); + startRinging(); } else { Log.d(Config.LOGTAG, id.account.getJid() + ": ignoring session proposal because already in " + state); } } + private void startRinging() { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing"); + final Intent intent = new Intent(xmppConnectionService, RtpSessionActivity.class); + intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString()); + intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + xmppConnectionService.startActivity(intent); + } + private void receiveProceed(final Jid from, final Element proceed) { if (from.equals(id.with)) { if (isInitiator()) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java index 53210e78c..f4b03a062 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java @@ -11,6 +11,9 @@ import com.google.common.util.concurrent.SettableFuture; import org.webrtc.AudioSource; import org.webrtc.AudioTrack; +import org.webrtc.Camera1Capturer; +import org.webrtc.Camera1Enumerator; +import org.webrtc.CameraVideoCapturer; import org.webrtc.DataChannel; import org.webrtc.IceCandidate; import org.webrtc.MediaConstraints; @@ -20,6 +23,9 @@ import org.webrtc.PeerConnectionFactory; import org.webrtc.RtpReceiver; import org.webrtc.SdpObserver; import org.webrtc.SessionDescription; +import org.webrtc.VideoCapturer; +import org.webrtc.VideoSource; +import org.webrtc.VideoTrack; import java.util.List; @@ -30,6 +36,9 @@ import eu.siacs.conversations.Config; public class WebRTCWrapper { + private VideoTrack localVideoTrack = null; + private VideoTrack remoteVideoTrack = null; + private final EventCallback eventCallback; private final PeerConnection.Observer peerConnectionObserver = new PeerConnection.Observer() { @@ -75,6 +84,11 @@ public class WebRTCWrapper { for(AudioTrack audioTrack : mediaStream.audioTracks) { Log.d(Config.LOGTAG,"remote? - audioTrack enabled:"+audioTrack.enabled()+" state="+audioTrack.state()); } + final List videoTracks = mediaStream.videoTracks; + if (videoTracks.size() > 0) { + Log.d(Config.LOGTAG, "more than zero remote video tracks found. using first"); + remoteVideoTrack = videoTracks.get(0); + } } @Override @@ -112,15 +126,65 @@ public class WebRTCWrapper { } public void initializePeerConnection() { - final PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory(); + CameraVideoCapturer capturer = null; + Camera1Enumerator camera1Enumerator = new Camera1Enumerator(); + 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 + public void onCameraError(String s) { + + } + + @Override + public void onCameraDisconnected() { + + } + + @Override + public void onCameraFreezed(String s) { + + } + + @Override + public void onCameraOpening(String s) { + Log.d(Config.LOGTAG,"onCameraOpening"); + } + + @Override + public void onFirstFrameAvailable() { + Log.d(Config.LOGTAG,"onFirstFrameAvailable"); + } + + @Override + public void onCameraClosed() { + + } + }); + } + } + + /*if (capturer != null) { + capturer.initialize(); + Log.d(Config.LOGTAG,"start capturing"); + capturer.startCapture(800,600,30); + }*/ + + final VideoSource videoSource = peerConnectionFactory.createVideoSource(false); + final VideoTrack videoTrack = peerConnectionFactory.createVideoTrack("my-video-track", videoSource); + 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()); final MediaStream stream = peerConnectionFactory.createLocalMediaStream("my-media-stream"); stream.addTrack(audioTrack); + //stream.addTrack(videoTrack); + + this.localVideoTrack = videoTrack; final List iceServers = ImmutableList.of( @@ -136,6 +200,8 @@ public class WebRTCWrapper { this.peerConnection = peerConnection; } + + public ListenableFuture createOffer() { return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> { final SettableFuture future = SettableFuture.create(); diff --git a/src/main/res/drawable-hdpi/ic_call_end_white_48dp.png b/src/main/res/drawable-hdpi/ic_call_end_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e1831d7afd086dcfc741a496d058af3d0308da99 GIT binary patch literal 553 zcmV+^0@nSBP)Ksbir@OQBE-g|t&k+Ykz+ zv_rwEC`K3YWfDSS5J7RvWL_XcKqYFppN>MvIXStxmwO?<=lKUdap+5>QmIrbl}e>j zGRKXZG-J-9Wt+BCRc+a{Y|)qQxnSHenb_~4{1ro{d|_SL)_iW#>#}--+KstyO|7k% z^}hD{fL?Las(SQ?8(uyLC^P13^={64vi*ZH6XrFlAAKO(59m$bE9xH$9-8v0VFP+~ zsHo`BYrtDhy5x~1|0(JlL*+odW>xLpwjW$JqEnQ(%e$_bmsizYJ$r#Zu_nI}QN!c% zTk&B&=mn1z_eM>icNF(P_imuq{7zFq{AzF~=!Cy%8i+rA{68pj1)2(ii!u?~%+L}b zZmWdrvtU;=W`?d^6guO|>85IXU^O5DfI3g62s-|^{I^FF~F-L?V(yCEW=O=9B zb417|EjTI~@JoKlw1WKR;N}vQvpae>w!v}f>M-hs<`NyOS00000NkvXXu0mjfwpIZY literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_call_white_48dp.png b/src/main/res/drawable-hdpi/ic_call_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..90ead2e4551b165530bd2430b3d69c34263c5c4e GIT binary patch literal 597 zcmV-b0;>IqP)a~F^ihkCNXidBsWB>X=;U*@F%!%#fVZaU}txjgmm7*kE>_wfD zJ4vghX)Y+W+A>RYW}(s9ms0kgvz_-nXXic7bMt;aQYw{7rQ+a|A;-#I(=OY{5am0Y zWfwW3^~f&rM7t`x_(`-r*+q_ML$ZrWqCJ#dj1g^AcJY*GIgD&#kT@-}i3`LzE}J+^ zoB`QH3vni76Nb;kX_ZZk5a)z!;v#YO$R>6Z?LI~}VVI$`08h4Yi&6qS*+(ZU3-IIu z>zHA=08g&aOR)e??y#Lg0iN9A2}>4ekZW`hc1f;bc*&AEHpw*(5q4XyVR%khr(9zf zd6rDFUaoP2usayJMLpAmosw%DC2WCxa*ZLvKCxA9QO8@t-q9$x*vU7-#@QgZ=w^|y zaT*l^!(L9ZMYTZ>h2FDG5%3w|pEvY#jAo3IgrT28vm8(f_+%;eg;zXakY28EhGta@ z!!U(@aT=p#@W~Qqp8cv8YZ#{3JsMO1pDg7VQ}r-hr`Qx-`VXHhbwLu%tSQXU{ z2YEroR7)7z38;u_k5;bnkuu2+*3!Wc)5OWiCJb$y=Ml4%G9VW)G||O5GCXFK4}9eZ jd2$TkDV0j4QgQwO?=x#gyQpL<00000NkvXXu0mjf@K6c} literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_call_end_white_48dp.png b/src/main/res/drawable-mdpi/ic_call_end_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a4fe6889d159cac861cac4f885ae3ec28cd9ca44 GIT binary patch literal 389 zcmV;00eb$4P)Gh#=i2 zxUHW#j;ZlmFB~yTpC3Sx}?~Nic9mw!VXE%t4-O|}Tsh_|+P54s)>dbrr zidFQ20(vVbVGTk9pdd6u1?s{B?p^l`+zDx(acj#Hu#H<)l7cYeNZ1sJc>*koG@S1d z!I?N=0P(RwPMz)%p_8y#Kp{S-Sj5)v5kV&^WRQT%Q2D;s0U^mDyCjevmSBfHh7cVH jZ3Zxa0SsV(e*t^~=a|RM72~P_00000NkvXXu0mjf^Vpp> literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_call_white_48dp.png b/src/main/res/drawable-mdpi/ic_call_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ef45e933a99b720cc5f6127e6da22bc2fa679244 GIT binary patch literal 420 zcmV;V0bBlwP)u7H4zjb0wVlEO#(-afhJ{~L_owyniLh<44m_hh=0)JC~(EtGz}i`o*rY-v?y@O z7&HsExZpoDD~cS_W+YkQAr(Fol6E6IIG(V_N51l%CO?U|VOMi=rhWlQl3!NbcvwOJ O0000E%2g55>;f$a!bnJ3^a-8Q&a-BDj#(M~HGj;g!I zhT#AT6Q-T;yKcMWxVr6%K>-T8JnM{J*Dz;?qQ8JmrhTEGeXj2M{s8XwmOl-mWk>Al zC7>{A!Js?kent0y!j#j7)u$d%bOX4{$I5r!N%LksY_|!UjT==ctTS%23A^nzW8O*U zmG474I|JO{4P{z(%A6@TiZ*tWDRVyYht{on)phLwYWDj8L-itux0`9nrkixxLt!a58z9;H3Llg znMwfo(S8319JESh0Q}{te*uN(pi%&sQ;0C)bt(zquv(a*vHpE0}6<4A=MUgDB6h!xmw?$P#D_ykG zL=hFSC`v&PZLuhB6vP_@=VGGKX8IHCrk*(yzZvID{vUkLBLzVa1VIo437F3S<}L zr)ZZ=%%^~hA`4^@1GpNLMLfgRh%BOnyC&Jg3*1eTJrr;^UH0$M-cTV>3Gwxo}CTrME zHM(UD8LF{E*6;z(an~(-ID@NuOqM-t!_8Bc$|63;MUD>HM8qB5B}b?1Vi)7f(<#eX z$ao5L$u=TxQb~b~>|-0rie%*jX7ZA9MV8AK{777pFXRuF5qDC4;R10P`GnQPT_ln} zi1>rJwekty5O<$e`GbfH#O;+&SVD=n{ma+#35SWhOPl<`Y=(&ICz3zdK)H?b2N7q9 z8>LJB;8XI%J>VnxgC5FVqgDRk80F5=B403-KPmSM&GH4Gk)zykn&k_=WsGva(xNKR z%J=lq!!$J>n@MtxRyiWeBmVObzthK;OjaYYha}heSPsZiAnp~{I7%Nqe8pU5F@+|j zhloQYc}Pa@K$Ze-MmR;g(m@mbBpGEhkt!lXfoc?4pmfkoKgoXLLnR_Zo@xy$Ei`eE zWcOI1GIWurdLv2?5xc2mKW+LSy2w)#rHf6Bk?aBMi1Y@XTphVqhBCv?_)QKhv zE4e})XyOpDiu1fDO*EF!&nPvM1*4F5EbdU*GfFjIneHf!T&u3Z-OsM5Qb8 zN9#sXwu~_BPAVY?l86#YGl}X+VTcbxx}8}LN{TF!!Usi2NR9HQ(!i)Dh@fn#$LZ#) zN0DM4^n1SN>>PLApa0?|ZVN5bX`PL>>#;|#yg`HVdhO9;yN%X)$1)4e zahAIR$6SncC99BF@LgwAZ-Ucr9La5>9$Ez zuPzT5D@wRA?y=flY1-`i;(?mHDP1obA3|xo zfHNKlUe$2AKvVq8umNI=Nv95!cu1aM1;hdOof=T1P8fDT@VW+tfsE75umxh1=0ZTz z>}FU4vCB0l1G-;7!ybr3=AH=!mJJ%$w#&_B5WEVVoGEHG9nw#g_k@h0lZjz@&7h&H=XRLEL&XTu{x z7DNX;p-xoL>MXFocpedoC)(g5QGpxpi__$369s`%5FN5WPE_a;kIEOrBSJAm+e{G^ zzR9+v=Mf=2(Q1vN3f8DIEsqH4hz30_5mmCpV+IQF+$;(Jr6B5ao2atgs;@9l3ZRn^ z?Q*%O!d<4PFi#qwaJ#%?`^AN#N;lq5j;&8y7Dt?ue5fDn_L7mJig&i9{s4X6GCsRI z>9b7GA}3V;66b36zsh>*{kt7HAOQdX01)*5bvpv_fm;d$2@)hokRU;V5F|*DAVGoz z2||z{L4pJc5+n#gf&>W?BuJ1TK?o8gNRS{wf&?K*kRU;mAOhFlPsF?ZQhopc002ov JPDHLkV1l-t*)jkC literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_call_white_48dp.png b/src/main/res/drawable-xxhdpi/ic_call_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a8e295a42f97bc49fb454a0584f77450d4e12a16 GIT binary patch literal 1134 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 literal 0 HcmV?d00001 diff --git a/src/main/res/layout/activity_rtp_session.xml b/src/main/res/layout/activity_rtp_session.xml new file mode 100644 index 000000000..dc7dc4eec --- /dev/null +++ b/src/main/res/layout/activity_rtp_session.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 074b5ae30..4332d1907 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -19,6 +19,7 @@ #ff424242 #ff282828 #fff44336 + #ffD32F2F #ffd50000 #ffff8a80 #ffc62828 diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml index 432f256c0..00ed0b3b5 100644 --- a/src/main/res/values/styles.xml +++ b/src/main/res/values/styles.xml @@ -1,11 +1,14 @@ - + + diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index 454f0ca6c..054194fbe 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -31,6 +31,7 @@ 14sp 16sp 20sp + 45sp 16sp 5sp 18sp