mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-10 22:34:15 +01:00
Lots of progress on WebSocket implementation
This commit is contained in:
parent
41bdcbd3c3
commit
5e546734cd
@ -190,11 +190,6 @@ dependencies {
|
|||||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||||
implementation 'com.kevalpatel2106:emoticongifkeyboard:1.1'
|
implementation 'com.kevalpatel2106:emoticongifkeyboard:1.1'
|
||||||
|
|
||||||
implementation 'com.github.tinder.scarlet:scarlet:0.1.5'
|
|
||||||
implementation 'com.github.tinder.scarlet:scarlet-stream-adapter-rxjava2:0.1.5'
|
|
||||||
implementation 'com.github.tinder.scarlet:scarlet-message-adapter-moshi:0.1.5'
|
|
||||||
implementation 'com.github.tinder.scarlet:scarlet-websocket-okhttp:0.1.5'
|
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation ('androidx.test.espresso:espresso-core:3.1.0-alpha4', {
|
androidTestImplementation ('androidx.test.espresso:espresso-core:3.1.0-alpha4', {
|
||||||
exclude group: 'com.android.support', module: 'support-annotations'
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.activities;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.webkit.SslErrorHandler;
|
||||||
|
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
|
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.events.CertificateEvent;
|
||||||
|
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
||||||
|
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
|
|
||||||
|
import java.security.cert.CertificateParsingException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
|
public class BaseActivity extends AppCompatActivity {
|
||||||
|
private static final String TAG = "BaseActivity";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
EventBus eventBus;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
|
||||||
|
@Nullable SslErrorHandler sslErrorHandler) {
|
||||||
|
DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
|
||||||
|
String validFrom = formatter.format(cert.getNotBefore());
|
||||||
|
String validUntil = formatter.format(cert.getNotAfter());
|
||||||
|
|
||||||
|
String issuedBy = cert.getIssuerDN().toString();
|
||||||
|
String issuedFor;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cert.getSubjectAlternativeNames() != null) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (Object o : cert.getSubjectAlternativeNames()) {
|
||||||
|
List list = (List) o;
|
||||||
|
int type = (Integer) list.get(0);
|
||||||
|
if (type == 2) {
|
||||||
|
String name = (String) list.get(1);
|
||||||
|
stringBuilder.append("[").append(type).append("]").append(name).append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
issuedFor = stringBuilder.toString();
|
||||||
|
} else {
|
||||||
|
issuedFor = cert.getSubjectDN().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StringFormatMatches") String dialogText = String.format(getResources()
|
||||||
|
.getString(R.string.nc_certificate_dialog_text),
|
||||||
|
issuedBy, issuedFor, validFrom, validUntil);
|
||||||
|
|
||||||
|
new LovelyStandardDialog(this)
|
||||||
|
.setTopColorRes(R.color.nc_darkRed)
|
||||||
|
.setNegativeButtonColorRes(R.color.nc_darkRed)
|
||||||
|
.setPositiveButtonColorRes(R.color.colorPrimaryDark)
|
||||||
|
.setIcon(R.drawable.ic_security_white_24dp)
|
||||||
|
.setTitle(R.string.nc_certificate_dialog_title)
|
||||||
|
.setMessage(dialogText)
|
||||||
|
.setPositiveButton(R.string.nc_yes, v -> {
|
||||||
|
magicTrustManager.addCertInTrustStore(cert);
|
||||||
|
if (sslErrorHandler != null) {
|
||||||
|
sslErrorHandler.proceed();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.nc_no, view1 -> {
|
||||||
|
if (sslErrorHandler != null) {
|
||||||
|
sslErrorHandler.cancel();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
|
||||||
|
} catch (CertificateParsingException e) {
|
||||||
|
Log.d(TAG, "Failed to parse the certificate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
public void onMessageEvent(CertificateEvent event) {
|
||||||
|
showCertificateDialog(event.getX509Certificate(), event.getMagicTrustManager(), event.getSslErrorHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
eventBus.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
eventBus.unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.activities;
|
|||||||
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@ -48,7 +47,7 @@ import butterknife.BindView;
|
|||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class MagicCallActivity extends AppCompatActivity {
|
public class MagicCallActivity extends BaseActivity {
|
||||||
private static final String TAG = "MagicCallActivity";
|
private static final String TAG = "MagicCallActivity";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -20,17 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.nextcloud.talk.activities;
|
package com.nextcloud.talk.activities;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.emoji.text.EmojiCompat;
|
|
||||||
import androidx.emoji.bundled.BundledEmojiCompatConfig;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.webkit.SslErrorHandler;
|
|
||||||
|
|
||||||
import com.bluelinelabs.conductor.Conductor;
|
import com.bluelinelabs.conductor.Conductor;
|
||||||
import com.bluelinelabs.conductor.Router;
|
import com.bluelinelabs.conductor.Router;
|
||||||
@ -43,23 +35,14 @@ import com.nextcloud.talk.controllers.ChatController;
|
|||||||
import com.nextcloud.talk.controllers.MagicBottomNavigationController;
|
import com.nextcloud.talk.controllers.MagicBottomNavigationController;
|
||||||
import com.nextcloud.talk.controllers.ServerSelectionController;
|
import com.nextcloud.talk.controllers.ServerSelectionController;
|
||||||
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
|
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
|
||||||
import com.nextcloud.talk.events.CertificateEvent;
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
|
||||||
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
|
||||||
import org.greenrobot.eventbus.ThreadMode;
|
|
||||||
|
|
||||||
import java.security.cert.CertificateParsingException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.emoji.bundled.BundledEmojiCompatConfig;
|
||||||
|
import androidx.emoji.text.EmojiCompat;
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -68,7 +51,7 @@ import io.requery.android.sqlcipher.SqlCipherDatabaseSource;
|
|||||||
import io.requery.reactivex.ReactiveEntityStore;
|
import io.requery.reactivex.ReactiveEntityStore;
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public final class MainActivity extends AppCompatActivity implements ActionBarProvider {
|
public final class MainActivity extends BaseActivity implements ActionBarProvider {
|
||||||
|
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
|
|
||||||
@ -84,9 +67,6 @@ public final class MainActivity extends AppCompatActivity implements ActionBarPr
|
|||||||
@Inject
|
@Inject
|
||||||
SqlCipherDatabaseSource sqlCipherDatabaseSource;
|
SqlCipherDatabaseSource sqlCipherDatabaseSource;
|
||||||
|
|
||||||
@Inject
|
|
||||||
EventBus eventBus;
|
|
||||||
|
|
||||||
private Router router;
|
private Router router;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -164,74 +144,4 @@ public final class MainActivity extends AppCompatActivity implements ActionBarPr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
|
|
||||||
@Nullable SslErrorHandler sslErrorHandler) {
|
|
||||||
DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
|
|
||||||
String validFrom = formatter.format(cert.getNotBefore());
|
|
||||||
String validUntil = formatter.format(cert.getNotAfter());
|
|
||||||
|
|
||||||
String issuedBy = cert.getIssuerDN().toString();
|
|
||||||
String issuedFor;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (cert.getSubjectAlternativeNames() != null) {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
for (Object o : cert.getSubjectAlternativeNames()) {
|
|
||||||
List list = (List) o;
|
|
||||||
int type = (Integer) list.get(0);
|
|
||||||
if (type == 2) {
|
|
||||||
String name = (String) list.get(1);
|
|
||||||
stringBuilder.append("[").append(type).append("]").append(name).append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
issuedFor = stringBuilder.toString();
|
|
||||||
} else {
|
|
||||||
issuedFor = cert.getSubjectDN().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StringFormatMatches") String dialogText = String.format(getResources()
|
|
||||||
.getString(R.string.nc_certificate_dialog_text),
|
|
||||||
issuedBy, issuedFor, validFrom, validUntil);
|
|
||||||
|
|
||||||
new LovelyStandardDialog(this)
|
|
||||||
.setTopColorRes(R.color.nc_darkRed)
|
|
||||||
.setNegativeButtonColorRes(R.color.nc_darkRed)
|
|
||||||
.setPositiveButtonColorRes(R.color.colorPrimaryDark)
|
|
||||||
.setIcon(R.drawable.ic_security_white_24dp)
|
|
||||||
.setTitle(R.string.nc_certificate_dialog_title)
|
|
||||||
.setMessage(dialogText)
|
|
||||||
.setPositiveButton(R.string.nc_yes, v -> {
|
|
||||||
magicTrustManager.addCertInTrustStore(cert);
|
|
||||||
if (sslErrorHandler != null) {
|
|
||||||
sslErrorHandler.proceed();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.nc_no, view1 -> {
|
|
||||||
if (sslErrorHandler != null) {
|
|
||||||
sslErrorHandler.cancel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
|
|
||||||
} catch (CertificateParsingException e) {
|
|
||||||
Log.d(TAG, "Failed to parse the certificate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
||||||
public void onMessageEvent(CertificateEvent event) {
|
|
||||||
showCertificateDialog(event.getX509Certificate(), event.getMagicTrustManager(), event.getSslErrorHandler());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
eventBus.register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
eventBus.unregister(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.api;
|
|
||||||
|
|
||||||
import com.nextcloud.talk.models.json.websocket.CallOverallWebSocketMessage;
|
|
||||||
import com.nextcloud.talk.models.json.websocket.HelloOverallWebSocketMessage;
|
|
||||||
import com.nextcloud.talk.models.json.websocket.HelloResponseWebSocketMessage;
|
|
||||||
import com.nextcloud.talk.models.json.websocket.RequestOfferOverallWebSocketMessage;
|
|
||||||
import com.nextcloud.talk.models.json.websocket.RoomOverallWebSocketMessage;
|
|
||||||
import com.tinder.scarlet.WebSocket;
|
|
||||||
import com.tinder.scarlet.ws.Receive;
|
|
||||||
import com.tinder.scarlet.ws.Send;
|
|
||||||
|
|
||||||
import io.reactivex.Flowable;
|
|
||||||
|
|
||||||
public interface ExternalSignaling {
|
|
||||||
@Receive
|
|
||||||
Flowable<WebSocket.Event.OnMessageReceived> observeOnMessageReceived();
|
|
||||||
|
|
||||||
@Receive
|
|
||||||
Flowable<WebSocket.Event.OnConnectionOpened> observeOnConnectionOpenedEvent();
|
|
||||||
|
|
||||||
@Receive
|
|
||||||
Flowable<WebSocket.Event.OnConnectionFailed> observeOnConnectionFailedEvent();
|
|
||||||
|
|
||||||
@Receive
|
|
||||||
Flowable<WebSocket.Event.OnConnectionClosed> observeOnConnectionClosedEvent();
|
|
||||||
|
|
||||||
@Send
|
|
||||||
void sendHello(HelloOverallWebSocketMessage helloOverallWebSocketMessage);
|
|
||||||
|
|
||||||
@Send
|
|
||||||
void sendResumeHello(RoomOverallWebSocketMessage roomOverallWebSocketMessage);
|
|
||||||
|
|
||||||
@Send
|
|
||||||
void sendOfferRequest(RequestOfferOverallWebSocketMessage requestOfferOverallWebSocketMessage);
|
|
||||||
|
|
||||||
@Send
|
|
||||||
void sendCallMessage(CallOverallWebSocketMessage callOverallWebSocketMessage);
|
|
||||||
|
|
||||||
@Receive
|
|
||||||
Flowable<HelloResponseWebSocketMessage> observeOnHelloBackEvent();
|
|
||||||
}
|
|
@ -50,7 +50,6 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||||||
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
|
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
|
||||||
import com.bumptech.glide.request.RequestOptions;
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.api.ExternalSignaling;
|
|
||||||
import com.nextcloud.talk.api.NcApi;
|
import com.nextcloud.talk.api.NcApi;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.base.BaseController;
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
@ -76,7 +75,6 @@ import com.nextcloud.talk.models.json.signaling.Signaling;
|
|||||||
import com.nextcloud.talk.models.json.signaling.SignalingOverall;
|
import com.nextcloud.talk.models.json.signaling.SignalingOverall;
|
||||||
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
|
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
|
||||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
|
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
|
||||||
import com.nextcloud.talk.models.json.websocket.HelloResponseWebSocketMessage;
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils;
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
import com.nextcloud.talk.utils.MagicFlipView;
|
import com.nextcloud.talk.utils.MagicFlipView;
|
||||||
import com.nextcloud.talk.utils.NotificationUtils;
|
import com.nextcloud.talk.utils.NotificationUtils;
|
||||||
@ -89,8 +87,7 @@ import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder;
|
|||||||
import com.nextcloud.talk.webrtc.MagicAudioManager;
|
import com.nextcloud.talk.webrtc.MagicAudioManager;
|
||||||
import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
|
import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
|
||||||
import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
|
import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
|
||||||
import com.nextcloud.talk.webrtc.ScarletHelper;
|
import com.nextcloud.talk.webrtc.WebSocketConnectionHelper;
|
||||||
import com.tinder.scarlet.WebSocket;
|
|
||||||
import com.wooplr.spotlight.SpotlightView;
|
import com.wooplr.spotlight.SpotlightView;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringEscapeUtils;
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
@ -98,7 +95,6 @@ import org.greenrobot.eventbus.EventBus;
|
|||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
import org.greenrobot.eventbus.ThreadMode;
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
import org.reactivestreams.Subscription;
|
|
||||||
import org.webrtc.AudioSource;
|
import org.webrtc.AudioSource;
|
||||||
import org.webrtc.AudioTrack;
|
import org.webrtc.AudioTrack;
|
||||||
import org.webrtc.Camera1Enumerator;
|
import org.webrtc.Camera1Enumerator;
|
||||||
@ -135,7 +131,6 @@ import butterknife.BindView;
|
|||||||
import butterknife.OnClick;
|
import butterknife.OnClick;
|
||||||
import butterknife.OnLongClick;
|
import butterknife.OnLongClick;
|
||||||
import eu.davidea.flipview.FlipView;
|
import eu.davidea.flipview.FlipView;
|
||||||
import io.reactivex.FlowableSubscriber;
|
|
||||||
import io.reactivex.Observer;
|
import io.reactivex.Observer;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
@ -249,8 +244,8 @@ public class CallController extends BaseController {
|
|||||||
private SpotlightView spotlightView;
|
private SpotlightView spotlightView;
|
||||||
|
|
||||||
private ExternalSignalingServer externalSignalingServer;
|
private ExternalSignalingServer externalSignalingServer;
|
||||||
private ExternalSignaling externalSignaling;
|
private okhttp3.WebSocket webSocketClient;
|
||||||
private ScarletHelper scarletHelper;
|
private WebSocketConnectionHelper webSocketConnectionHelper;
|
||||||
|
|
||||||
public CallController(Bundle args) {
|
public CallController(Bundle args) {
|
||||||
super(args);
|
super(args);
|
||||||
@ -1158,7 +1153,7 @@ public class CallController extends BaseController {
|
|||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setUpAndInitiateScarletConnection();
|
setupAndInitiateWebSocketsConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,55 +1168,11 @@ public class CallController extends BaseController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpAndInitiateScarletConnection() {
|
private void setupAndInitiateWebSocketsConnection() {
|
||||||
scarletHelper = new ScarletHelper();
|
webSocketConnectionHelper = new WebSocketConnectionHelper();
|
||||||
externalSignaling = scarletHelper.getExternalSignalingInstanceForServer(
|
webSocketClient = webSocketConnectionHelper.getExternalSignalingInstanceForServer(
|
||||||
externalSignalingServer.getExternalSignalingServer(), false);
|
externalSignalingServer.getExternalSignalingServer(), false,
|
||||||
|
conversationUser, externalSignalingServer.getExternalSignalingTicket());
|
||||||
externalSignaling.observeOnHelloBackEvent().subscribe(new FlowableSubscriber<HelloResponseWebSocketMessage>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(HelloResponseWebSocketMessage helloResponseWebSocketMessage) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
externalSignaling.observeOnConnectionOpenedEvent().subscribe(new FlowableSubscriber<WebSocket.Event.OnConnectionOpened>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(WebSocket.Event.OnConnectionOpened onConnectionOpened) {
|
|
||||||
externalSignaling.sendHello(scarletHelper.getAssembledHelloModel(conversationUser,
|
|
||||||
externalSignalingServer.getExternalSignalingTicket()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick({R.id.pip_video_view, R.id.remote_renderers_layout})
|
@OnClick({R.id.pip_video_view, R.id.remote_renderers_layout})
|
||||||
|
@ -20,9 +20,12 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.models;
|
package com.nextcloud.talk.models;
|
||||||
|
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Parcel
|
||||||
public class ExternalSignalingServer {
|
public class ExternalSignalingServer {
|
||||||
String externalSignalingServer;
|
String externalSignalingServer;
|
||||||
String externalSignalingTicket;
|
String externalSignalingTicket;
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.models.json.websocket;
|
|||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import com.squareup.moshi.Json;
|
|
||||||
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
@ -35,6 +34,6 @@ public class AuthParametersWebSocketMessage {
|
|||||||
@JsonField(name = "userid")
|
@JsonField(name = "userid")
|
||||||
String userid;
|
String userid;
|
||||||
|
|
||||||
@Json(name = "ticket")
|
@JsonField(name = "ticket")
|
||||||
String ticket;
|
String ticket;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.models.json.websocket;
|
|||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import com.squareup.moshi.Json;
|
|
||||||
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.models.json.websocket;
|
|||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import com.squareup.moshi.Json;
|
|
||||||
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.models.json.websocket;
|
|||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import com.squareup.moshi.Json;
|
|
||||||
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.models.json.websocket;
|
|||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import com.squareup.moshi.Json;
|
|
||||||
|
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.webrtc;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.bluelinelabs.logansquare.LoganSquare;
|
||||||
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
|
import com.nextcloud.talk.models.json.websocket.BaseWebSocketMessage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.WebSocket;
|
||||||
|
import okhttp3.WebSocketListener;
|
||||||
|
import okio.ByteString;
|
||||||
|
|
||||||
|
public class MagicWebSocketListener extends WebSocketListener {
|
||||||
|
private static final String TAG = "MagicWebSocketListener";
|
||||||
|
private static final int NORMAL_CLOSURE_STATUS = 1000;
|
||||||
|
|
||||||
|
private UserEntity conversationUser;
|
||||||
|
private String webSocketTicket;
|
||||||
|
private String resumeId;
|
||||||
|
private WebSocketConnectionHelper webSocketConnectionHelper;
|
||||||
|
|
||||||
|
MagicWebSocketListener(UserEntity conversationUser, String webSocketTicket) {
|
||||||
|
this.conversationUser = conversationUser;
|
||||||
|
this.webSocketTicket = webSocketTicket;
|
||||||
|
this.webSocketConnectionHelper = new WebSocketConnectionHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(WebSocket webSocket, Response response) {
|
||||||
|
try {
|
||||||
|
if (TextUtils.isEmpty(resumeId)) {
|
||||||
|
Log.d("MARIO", LoganSquare.serialize(webSocketConnectionHelper.getAssembledHelloModel(conversationUser, webSocketTicket)));
|
||||||
|
webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledHelloModel(conversationUser, webSocketTicket)));
|
||||||
|
} else {
|
||||||
|
webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledHelloModelForResume(resumeId)));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to serialize hello model");
|
||||||
|
}
|
||||||
|
//webSocket.close(NORMAL_CLOSURE_STATUS, "Goodbye !");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(WebSocket webSocket, String text) {
|
||||||
|
Log.d(TAG, "Receiving : " + text);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BaseWebSocketMessage baseWebSocketMessage = LoganSquare.parse(text, BaseWebSocketMessage.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to parse base WebSocket message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(WebSocket webSocket, ByteString bytes) {
|
||||||
|
Log.d(TAG, "Receiving bytes : " + bytes.hex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClosing(WebSocket webSocket, int code, String reason) {
|
||||||
|
webSocket.close(NORMAL_CLOSURE_STATUS, null);
|
||||||
|
Log.d(TAG, "Closing : " + code + " / " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||||
|
Log.d(TAG, "Error : " + t.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,13 +20,9 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.webrtc;
|
package com.nextcloud.talk.webrtc;
|
||||||
|
|
||||||
import com.google.android.gms.common.api.Api;
|
|
||||||
import com.nextcloud.talk.api.ExternalSignaling;
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.models.database.UserEntity;
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.models.json.rooms.Conversation;
|
|
||||||
import com.nextcloud.talk.models.json.signaling.NCMessageWrapper;
|
import com.nextcloud.talk.models.json.signaling.NCMessageWrapper;
|
||||||
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage;
|
|
||||||
import com.nextcloud.talk.models.json.websocket.AuthParametersWebSocketMessage;
|
import com.nextcloud.talk.models.json.websocket.AuthParametersWebSocketMessage;
|
||||||
import com.nextcloud.talk.models.json.websocket.AuthWebSocketMessage;
|
import com.nextcloud.talk.models.json.websocket.AuthWebSocketMessage;
|
||||||
import com.nextcloud.talk.models.json.websocket.CallOverallWebSocketMessage;
|
import com.nextcloud.talk.models.json.websocket.CallOverallWebSocketMessage;
|
||||||
@ -40,11 +36,6 @@ import com.nextcloud.talk.models.json.websocket.RoomOverallWebSocketMessage;
|
|||||||
import com.nextcloud.talk.models.json.websocket.RoomWebSocketMessage;
|
import com.nextcloud.talk.models.json.websocket.RoomWebSocketMessage;
|
||||||
import com.nextcloud.talk.models.json.websocket.SignalingDataWebSocketMessageForOffer;
|
import com.nextcloud.talk.models.json.websocket.SignalingDataWebSocketMessageForOffer;
|
||||||
import com.nextcloud.talk.utils.ApiUtils;
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
import com.tinder.scarlet.Scarlet;
|
|
||||||
import com.tinder.scarlet.messageadapter.moshi.MoshiMessageAdapter;
|
|
||||||
import com.tinder.scarlet.retry.LinearBackoffStrategy;
|
|
||||||
import com.tinder.scarlet.streamadapter.rxjava2.RxJava2StreamAdapterFactory;
|
|
||||||
import com.tinder.scarlet.websocket.okhttp.OkHttpClientUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -52,17 +43,20 @@ import java.util.Map;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
|
import io.requery.Nullable;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.WebSocket;
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class ScarletHelper {
|
public class WebSocketConnectionHelper {
|
||||||
private Map<String, ExternalSignaling> externalSignalingMap = new HashMap<>();
|
private Map<String, WebSocket> webSocketMap = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
OkHttpClient okHttpClient;
|
OkHttpClient okHttpClient;
|
||||||
|
|
||||||
|
|
||||||
public ScarletHelper() {
|
public WebSocketConnectionHelper() {
|
||||||
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,21 +72,19 @@ public class ScarletHelper {
|
|||||||
return generatedURL;
|
return generatedURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalSignaling getExternalSignalingInstanceForServer(String url, boolean forceReconnect) {
|
public WebSocket getExternalSignalingInstanceForServer(String url, boolean forceReconnect, UserEntity userEntity, String webSocketTicket) {
|
||||||
|
|
||||||
String connectionUrl = getExternalSignalingServerUrlFromSettingsUrl(url);
|
String connectionUrl = getExternalSignalingServerUrlFromSettingsUrl(url);
|
||||||
|
|
||||||
if (externalSignalingMap.containsKey(connectionUrl) && !forceReconnect) {
|
if (webSocketMap.containsKey(connectionUrl) && !forceReconnect) {
|
||||||
return externalSignalingMap.get(connectionUrl);
|
return webSocketMap.get(connectionUrl);
|
||||||
} else {
|
} else {
|
||||||
Scarlet scarlet = new Scarlet.Builder()
|
Request request = new Request.Builder().url(connectionUrl).build();
|
||||||
.backoffStrategy(new LinearBackoffStrategy(500))
|
MagicWebSocketListener listener = new MagicWebSocketListener(userEntity, webSocketTicket);
|
||||||
.webSocketFactory(OkHttpClientUtils.newWebSocketFactory(okHttpClient, connectionUrl))
|
WebSocket webSocket = okHttpClient.newWebSocket(request, listener);
|
||||||
.addMessageAdapterFactory(new MoshiMessageAdapter.Factory())
|
|
||||||
.addStreamAdapterFactory(new RxJava2StreamAdapterFactory())
|
webSocketMap.put(connectionUrl, webSocket);
|
||||||
.build();
|
return webSocket;
|
||||||
ExternalSignaling externalSignaling = scarlet.create(ExternalSignaling.class);
|
|
||||||
externalSignalingMap.put(connectionUrl, externalSignaling);
|
|
||||||
return externalSignaling;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +100,7 @@ public class ScarletHelper {
|
|||||||
authParametersWebSocketMessage.setUserid(userEntity.getUserId());
|
authParametersWebSocketMessage.setUserid(userEntity.getUserId());
|
||||||
authWebSocketMessage.setAuthParametersWebSocketMessage(authParametersWebSocketMessage);
|
authWebSocketMessage.setAuthParametersWebSocketMessage(authParametersWebSocketMessage);
|
||||||
helloWebSocketMessage.setAuthWebSocketMessage(authWebSocketMessage);
|
helloWebSocketMessage.setAuthWebSocketMessage(authWebSocketMessage);
|
||||||
|
helloOverallWebSocketMessage.setHelloWebSocketMessage(helloWebSocketMessage);
|
||||||
return helloOverallWebSocketMessage;
|
return helloOverallWebSocketMessage;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user