Much progress

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2017-11-11 05:39:01 +01:00
parent 56aeb30923
commit 15586bc0cc
29 changed files with 547 additions and 171 deletions

229
.idea/codeStyleSettings.xml Normal file
View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

View File

@ -77,8 +77,8 @@ dependencies {
implementation 'com.bluelinelabs:conductor-support:2.1.4'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.6.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.bluelinelabs:logansquare:1.3.7'
annotationProcessor 'com.bluelinelabs:logansquare-compiler:1.3.7'

View File

@ -29,21 +29,27 @@ import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.api.helpers.api.ApiHelper;
import com.nextcloud.talk.api.models.json.call.CallOverall;
import com.nextcloud.talk.api.models.json.generic.GenericOverall;
import com.nextcloud.talk.api.models.json.participants.Participant;
import com.nextcloud.talk.api.models.json.signaling.NCMessageWrapper;
import com.nextcloud.talk.api.models.json.signaling.Signaling;
import com.nextcloud.talk.api.models.json.signaling.SignalingOverall;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.webrtc.MagicPeerConnectionObserver;
import com.nextcloud.talk.webrtc.MagicSdpObserver;
import org.parceler.Parcels;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
@ -67,7 +73,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.functions.BooleanSupplier;
import javax.inject.Inject;
import autodagger.AutoInjector;
@ -76,6 +82,7 @@ import butterknife.ButterKnife;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BooleanSupplier;
import io.reactivex.schedulers.Schedulers;
import ru.alexbykov.nopermission.PermissionHelper;
@ -91,10 +98,6 @@ public class CallActivity extends AppCompatActivity {
@Inject
NcApi ncApi;
private String roomToken;
private UserEntity userEntity;
PeerConnectionFactory peerConnectionFactory;
MediaConstraints audioConstraints;
MediaConstraints videoConstraints;
@ -104,20 +107,25 @@ public class CallActivity extends AppCompatActivity {
AudioSource audioSource;
AudioTrack localAudioTrack;
VideoCapturer videoCapturer;
VideoRenderer localRenderer;
VideoRenderer remoteRenderer;
PeerConnection localPeer, remotePeer;
boolean inCall = true;
BooleanSupplier booleanSupplier = () -> inCall;
boolean leavingCall = false;
BooleanSupplier booleanSupplier = () -> leavingCall;
Disposable signalingDisposable;
Disposable pingDisposable;
List<PeerConnection.IceServer> iceServers;
private String roomToken;
private UserEntity userEntity;
private String callSession;
private String credentials;
private static int getSystemUiVisibility() {
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
return flags;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -135,8 +143,10 @@ public class CallActivity extends AppCompatActivity {
ButterKnife.bind(this);
roomToken = getIntent().getExtras().getString("roomToken", "");
userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable("userEntity"));
userEntity = getIntent().getExtras().getParcelable("userEntity");
callSession = getIntent().getExtras().getString("callSession", "");
credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
initViews();
PermissionHelper permissionHelper = new PermissionHelper(this);
@ -157,8 +167,6 @@ public class CallActivity extends AppCompatActivity {
}
private VideoCapturer createVideoCapturer() {
videoCapturer = createCameraCapturer(new Camera1Enumerator(false));
return videoCapturer;
@ -256,119 +264,202 @@ public class CallActivity extends AppCompatActivity {
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
//creating localPeer
localPeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints,
new MagicPeerConnectionObserver() {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
onIceCandidateReceived(localPeer, iceCandidate);
}
});
//creating local mediastream
MediaStream stream = peerConnectionFactory.createLocalMediaStream("102");
stream.addTrack(localAudioTrack);
stream.addTrack(localVideoTrack);
localPeer.addStream(stream);
// Start pulling signaling messages
ncApi.pullSignalingMessages(ApiHelper.getCredentials(userEntity.getUsername(),
userEntity.getToken()), ApiHelper.getUrlForSignaling(userEntity.getBaseUrl()))
ncApi.joinRoom(credentials, ApiHelper.getUrlForJoinRoom(userEntity.getBaseUrl(), roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.repeatWhen(observable -> observable.delay(1500, TimeUnit.MILLISECONDS))
.repeatUntil(booleanSupplier)
.retry(3)
.subscribe(new Observer<SignalingOverall>() {
.subscribe(new Observer<CallOverall>() {
@Override
public void onSubscribe(Disposable d) {
signalingDisposable = d;
}
@Override
public void onNext(SignalingOverall signalingOverall) {
if (signalingOverall.getOcs().getSignalings() != null) {
for (int i = 0; i < signalingOverall.getOcs().getSignalings().size(); i++) {
try {
receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void onNext(CallOverall callOverall) {
ncApi.joinCall(credentials,
ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(GenericOverall genericOverall) {
callSession = callOverall.getOcs().getData().getSessionId();
// start pinging the call
ncApi.pingCall(ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
ApiHelper.getUrlForCallPing(userEntity.getBaseUrl(), roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.repeatWhen(observable -> observable.delay(5000, TimeUnit.MILLISECONDS))
.repeatUntil(booleanSupplier)
.retry(3)
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(Disposable d) {
pingDisposable = d;
}
@Override
public void onNext(GenericOverall genericOverall) {
}
@Override
public void onError(Throwable e) {
dispose(pingDisposable);
}
@Override
public void onComplete() {
dispose(pingDisposable);
}
});
// Start pulling signaling messages
ncApi.pullSignalingMessages(ApiHelper.getCredentials(userEntity.getUsername(),
userEntity.getToken()), ApiHelper.getUrlForSignaling(userEntity.getBaseUrl()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.repeatWhen(observable -> observable.delay(1500, TimeUnit.MILLISECONDS))
.repeatUntil(booleanSupplier)
.retry(3)
.subscribe(new Observer<SignalingOverall>() {
@Override
public void onSubscribe(Disposable d) {
signalingDisposable = d;
}
@Override
public void onNext(SignalingOverall signalingOverall) {
if (signalingOverall.getOcs().getSignalings() != null) {
for (int i = 0; i < signalingOverall.getOcs().getSignalings().size(); i++) {
try {
receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onError(Throwable e) {
dispose(signalingDisposable);
}
@Override
public void onComplete() {
dispose(signalingDisposable);
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void onError(Throwable e) {
dispose(signalingDisposable);
}
@Override
public void onComplete() {
dispose(signalingDisposable);
}
});
}
// start pinging the call
ncApi.pingCall(ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
ApiHelper.getUrlForCallPing(userEntity.getBaseUrl(), roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.repeatWhen(observable -> observable.delay(5000, TimeUnit.MILLISECONDS))
.repeatUntil(booleanSupplier)
.retry(3)
.subscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
pingDisposable = d;
}
private void receivedSignalingMessage(Signaling signaling) throws IOException {
String messageType = signaling.getType();
@Override
public void onNext(Void aVoid) {
if (leavingCall) {
return;
}
}
@Override
public void onError(Throwable e) {
dispose(pingDisposable);
}
@Override
public void onComplete() {
dispose(pingDisposable);
}
});
if ("usersInRoom".equals(messageType)) {
processUsersInRoom((List<Participant>) signaling.getMessageWrapper());
} else if ("message".equals(messageType)) {
NCMessageWrapper ncSignalingMessage = LoganSquare.parse(signaling.getMessageWrapper().toString(),
NCMessageWrapper.class);
if (ncSignalingMessage.getSignalingMessage().getRoomType().equals("video")) {
switch (ncSignalingMessage.getSignalingMessage().getType()) {
case "offer":
break;
case "answer":
break;
case "candidate":
break;
default:
break;
}
}
} else {
Log.d(TAG, "Something went very very wrong");
}
}
private void processUsersInRoom(List<Participant> users) {
}
private void call() {
//creating localPeer
localPeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints,
new MagicPeerConnectionObserver() {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
onIceCandidateReceived(localPeer, iceCandidate);
}
});
//creating remotePeer
remotePeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints,
new MagicPeerConnectionObserver() {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
onIceCandidateReceived(remotePeer, iceCandidate);
}
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
onIceCandidateReceived(remotePeer, iceCandidate);
}
public void onAddStream(MediaStream mediaStream) {
super.onAddStream(mediaStream);
gotRemoteStream(mediaStream);
}
public void onAddStream(MediaStream mediaStream) {
super.onAddStream(mediaStream);
gotRemoteStream(mediaStream);
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
super.onIceGatheringChange(iceGatheringState);
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
super.onIceGatheringChange(iceGatheringState);
}
});
}
});
//creating Offer
localPeer.createOffer(new MagicSdpObserver(){
localPeer.createOffer(new MagicSdpObserver() {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
//we have localOffer. Set it as local desc for localpeer and remote desc for remote peer.
@ -390,10 +481,9 @@ public class CallActivity extends AppCompatActivity {
}, sdpConstraints);
}
private void hangup() {
inCall = false;
leavingCall = true;
dispose(null);
@ -413,6 +503,32 @@ public class CallActivity extends AppCompatActivity {
pipVideoView.release();
fullScreenVideoView.release();
String credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
ncApi.leaveCall(credentials, ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(GenericOverall genericOverall) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
private void gotRemoteStream(MediaStream stream) {
@ -444,14 +560,8 @@ public class CallActivity extends AppCompatActivity {
@Override
public void onDestroy() {
hangup();
super.onDestroy();
}
private static int getSystemUiVisibility() {
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
return flags;
hangup();
}
private void dispose(@Nullable Disposable disposable) {

View File

@ -111,7 +111,7 @@ public final class MainActivity extends AppCompatActivity implements ActionBarPr
}
public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
@Nullable SslErrorHandler sslErrorHandler) {
@Nullable SslErrorHandler sslErrorHandler) {
DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
String validFrom = formatter.format(cert.getNotBefore());
String validUntil = formatter.format(cert.getNotAfter());
@ -140,8 +140,8 @@ public final class MainActivity extends AppCompatActivity implements ActionBarPr
issuedBy, issuedFor, validFrom, validUntil);
new LovelyStandardDialog(this)
.setTopColorRes(R.color.darkRed)
.setNegativeButtonColorRes(R.color.darkRed)
.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)

View File

@ -133,23 +133,30 @@ public interface NcApi {
@GET
Observable<ParticipantsOverall> getPeersForCall(@Header("Authorization") String authorization, @Url String url);
@POST
Observable<CallOverall> joinRoom(@Header("Authorization") String authorization, @Url String url);
@DELETE
Observable<GenericOverall> leaveRoom(@Header("Authorization") String authorization, @Url String url);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/
@POST
Observable<CallOverall> joinCall(@Header("Authorization") String authorization, @Url String url);
Observable<GenericOverall> joinCall(@Header("Authorization") String authorization, @Url String url);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/
@DELETE
Observable<GenericOverall> leaveCall(@Header("Authorization") String authorization, @Url String url);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken/ping
*/
@POST
Observable<Void> pingCall(@Header("Authorization") String authorization, @Url String url);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/
@DELETE
Observable<Void> leaveCall(@Header("Authorization") String authorization, @Url String url);
Observable<GenericOverall> pingCall(@Header("Authorization") String authorization, @Url String url);
/*
QueryMap items are as follows:
@ -220,7 +227,7 @@ public interface NcApi {
*/
@DELETE
Observable<Void> unregisterDeviceForNotificationsWithProxy(@Header("Authorization") String authorization,
@Url String url,
@QueryMap Map<String, String> fields);
@Url String url,
@QueryMap Map<String, String> fields);
}

View File

@ -57,6 +57,10 @@ public class ApiHelper {
return retrofitBucket;
}
public static String getUrlForJoinRoom(String baseUrl, String token) {
return getRoom(baseUrl, token) + "/participants/active";
}
public static String getUrlForGetRooms(String baseUrl) {
return baseUrl + ocsApiVersion + spreedApiVersion + "/room";
}
@ -115,6 +119,7 @@ public class ApiHelper {
public static String getUrlForCall(String baseUrl, String token) {
return baseUrl + ocsApiVersion + spreedApiVersion + "/call/" + token;
}
public static String getUrlForCallPing(String baseUrl, String token) {

View File

@ -35,7 +35,7 @@ public class GenericMeta {
String status;
@JsonField(name = "statuscode")
String statusCode;
int statusCode;
@JsonField(name = "message")
String message;

View File

@ -42,4 +42,7 @@ public class Participant {
@JsonField(name = "roomId")
long roomId;
@JsonField(name = "inCall")
boolean inCall;
}

View File

@ -34,7 +34,7 @@ import lombok.Data;
public class Signaling {
@JsonField(name = "type")
String type;
//can be NCSignalingMessage or List<Participant>
//can be NCMessageWrapper or List<Participant>
@JsonField(name = "data")
Object signalingMessage;
Object messageWrapper;
}

View File

@ -98,6 +98,7 @@ public class NextcloudTalkApplication extends MultiDexApplication {
new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow().build().schedule();
new JobRequest.Builder(AccountRemovalJob.TAG).setUpdateCurrent(true).startNow().build().schedule();
}

View File

@ -47,14 +47,13 @@ import android.view.inputmethod.EditorInfo;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.CallActivity;
import com.nextcloud.talk.adapters.items.RoomItem;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.api.helpers.api.ApiHelper;
import com.nextcloud.talk.api.models.json.call.CallOverall;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.persistence.entities.UserEntity;
@ -73,9 +72,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Credentials;
import retrofit2.HttpException;
@AutoInjector(NextcloudTalkApplication.class)
@ -110,26 +107,15 @@ public class CallsListController extends BaseController implements SearchView.On
@Override
public boolean onItemClick(int position) {
if (roomItems.size() > position) {
overridePushHandler(new NoOpControllerChangeHandler());
overridePopHandler(new NoOpControllerChangeHandler());
RoomItem roomItem = roomItems.get(position);
ncApi.joinCall(Credentials.basic(userEntity.getUsername(), userEntity.getToken()),
ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomItem.getModel().getToken()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<CallOverall>() {
@Override
public void accept(CallOverall callOverall) throws Exception {
overridePushHandler(new SimpleSwapChangeHandler());
overridePopHandler(new SimpleSwapChangeHandler());
Intent callIntent = new Intent(getActivity(), CallActivity.class);
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
bundleBuilder.putString("roomToken", roomItem.getModel().getToken());
bundleBuilder.putParcelable("userEntity", userEntity);
callIntent.putExtras(bundleBuilder.build());
startActivity(callIntent);
}
});
Intent callIntent = new Intent(getActivity(), CallActivity.class);
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
bundleBuilder.putString("roomToken", roomItem.getModel().getToken());
bundleBuilder.putParcelable("userEntity", userEntity);
callIntent.putExtras(bundleBuilder.build());
startActivity(callIntent);
}
return true;

View File

@ -340,7 +340,7 @@ public class SettingsController extends BaseController {
messageView.setVisibility(View.VISIBLE);
break;
case WRONG_ACCOUNT:
messageText.setTextColor(getResources().getColor(R.color.darkRed));
messageText.setTextColor(getResources().getColor(R.color.nc_darkRed));
messageText.setText(getResources().getString(R.string.nc_settings_wrong_account));
messageView.setVisibility(View.VISIBLE);
break;
@ -424,6 +424,11 @@ public class SettingsController extends BaseController {
}
}
@Override
protected String getTitle() {
return getResources().getString(R.string.nc_app_name);
}
private class ProxyCredentialsChangeListener implements OnPreferenceValueChangedListener<Boolean> {
@Override
@ -462,9 +467,4 @@ public class SettingsController extends BaseController {
}
}
@Override
protected String getTitle() {
return getResources().getString(R.string.nc_app_name);
}
}

View File

@ -118,7 +118,7 @@ public class SwitchAccountController extends BaseController {
User user;
UserEntity currentUserEntity = userUtils.getCurrentUser();
for(Object userEntityObject : userUtils.getUsers()) {
for (Object userEntityObject : userUtils.getUsers()) {
userEntity = (UserEntity) userEntityObject;
if (!userEntity.equals(currentUserEntity)) {
user = new User();

View File

@ -236,7 +236,7 @@ public class WebViewLoginController extends BaseController {
if (userUtils.checkIfUserIsScheduledForDeletion(loginData.getUsername(), baseUrl)) {
ErrorMessageHolder.getInstance().setMessageType(
ErrorMessageHolder.ErrorMessageType.ACCOUNT_SCHEDULED_FOR_DELETION);
getRouter().popToRoot();
getRouter().popToRoot();
}
// We use the URL user entered because one provided by the server is NOT reliable

View File

@ -30,6 +30,7 @@ import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
public abstract class BaseController extends RefWatchingController {
private static final String TAG = "BaseController";
protected BaseController() {
}

View File

@ -34,6 +34,7 @@ import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;
import java.io.IOException;
import java.net.CookieManager;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
@ -47,6 +48,7 @@ import okhttp3.Authenticator;
import okhttp3.Cache;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.JavaNetCookieJar;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
@ -121,6 +123,8 @@ public class RestModule {
httpClient.readTimeout(30, TimeUnit.SECONDS);
httpClient.writeTimeout(30, TimeUnit.SECONDS);
httpClient.cookieJar(new JavaNetCookieJar(new CookieManager()));
int cacheSize = 128 * 1024 * 1024; // 128 MB
httpClient.cache(new Cache(NextcloudTalkApplication.getSharedApplication().getCacheDir(), cacheSize));

View File

@ -30,7 +30,8 @@ import java.security.cert.X509Certificate;
public class CertificateEvent {
private final X509Certificate x509Certificate;
private final MagicTrustManager magicTrustManager;
@Nullable private final SslErrorHandler sslErrorHandler;
@Nullable
private final SslErrorHandler sslErrorHandler;
public CertificateEvent(X509Certificate x509Certificate, MagicTrustManager magicTrustManager,
@Nullable SslErrorHandler sslErrorHandler) {

View File

@ -61,7 +61,7 @@ public class AccountRemovalJob extends Job {
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
PushConfigurationState pushConfigurationState;
for(Object userEntityObject : userUtils.getUsersScheduledForDeletion()) {
for (Object userEntityObject : userUtils.getUsersScheduledForDeletion()) {
UserEntity userEntity = (UserEntity) userEntityObject;
try {
if (!TextUtils.isEmpty(userEntity.getPushConfigurationState())) {
@ -78,8 +78,8 @@ public class AccountRemovalJob extends Job {
@Override
public void onNext(GenericOverall genericOverall) {
if (genericOverall.getOcs().getMeta().getStatusCode().equals("200")
|| genericOverall.getOcs().getMeta().getStatusCode().equals("202")) {
if (genericOverall.getOcs().getMeta().getStatusCode() == 200
|| genericOverall.getOcs().getMeta().getStatusCode() == 202) {
HashMap<String, String> queryMap = new HashMap<>();
queryMap.put("deviceIdentifier", finalPushConfigurationState.deviceIdentifier);
queryMap.put("userPublicKey", finalPushConfigurationState.getUserPublicKey());
@ -158,7 +158,7 @@ public class AccountRemovalJob extends Job {
}
});
}
} catch(IOException e) {
} catch (IOException e) {
Log.d(TAG, "Something went wrong while removing job at parsing PushConfigurationState");
userUtils.deleteUser(userEntity.getUsername(),
userEntity.getBaseUrl());

View File

@ -28,10 +28,10 @@ public class DisplayHelper {
private static final String TAG = "DIsplayHelper";
public static float convertDpToPixel(float dp, Context context){
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
float px = dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
return px;
}
}

View File

@ -23,13 +23,9 @@ package com.nextcloud.talk.utils;
import android.support.annotation.Nullable;
public class ErrorMessageHolder {
public enum ErrorMessageType {
WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, ACCOUNT_SCHEDULED_FOR_DELETION
}
private static final ErrorMessageHolder holder = new ErrorMessageHolder();
private ErrorMessageType errorMessageType;
private static final ErrorMessageHolder holder = new ErrorMessageHolder();
public static ErrorMessageHolder getInstance() {
return holder;
}
@ -42,6 +38,9 @@ public class ErrorMessageHolder {
this.errorMessageType = errorMessageType;
}
public enum ErrorMessageType {
WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, ACCOUNT_SCHEDULED_FOR_DELETION
}
}

View File

@ -335,7 +335,8 @@ public class PushUtils {
if (readPublicKey) {
keyString = keyString.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----",
"").replace("-----END PUBLIC KEY-----", "");;
"").replace("-----END PUBLIC KEY-----", "");
;
} else {
keyString = keyString.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----",
"").replace("-----END PRIVATE KEY-----", "");

View File

@ -65,7 +65,6 @@ public class UserUtils {
}
public UserEntity getAnyUserAndSetAsActive() {
Result findUserQueryResult = dataStore.select(User.class)
.where(UserEntity.SCHEDULED_FOR_DELETION.eq(false))
@ -125,6 +124,7 @@ public class UserUtils {
return false;
}
public boolean getIfUserWithUsernameAndServer(String username, String server) {
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username)
.and(UserEntity.BASE_URL.eq(server.toLowerCase())))

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#fff"
android:strokeWidth="0.14"
android:pathData="M7.9992,0.999 A6.9994,6.9993,0,0,0,1,7.9986 A6.9994,6.9993,0,0,0,7.9992,14.998
A6.9994,6.9993,0,0,0,11.63,13.974 C12.4902,14.3158,14.4171,15.33,14.8757,14.8919
C15.3549,14.4343,14.3131,12.2803,14.0633,11.4799
A6.9994,6.9993,0,0,0,14.9983,7.9985 A6.9994,6.9993,0,0,0,7.9992,0.9992 Z
M8,3.6601 A4.3401,4.34,0,0,1,12.34,8.0002 A4.3401,4.34,0,0,1,8,12.34
A4.3401,4.34,0,0,1,3.66,8.0002 A4.3401,4.34,0,0,1,8,3.6601 Z" />
</vector>

View File

@ -23,7 +23,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/nc_background_color">
android:background="@color/nc_white_color">
<ProgressBar
android:id="@+id/progress_bar"

View File

@ -24,7 +24,7 @@
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/nc_background_color">
android:background="@color/nc_white_color">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"

View File

@ -23,7 +23,16 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/nc_background_color">
android:background="@color/colorPrimary">
<ImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_above="@id/text_field_boxes"
android:layout_centerHorizontal="true"
android:layout_marginBottom="36dp"
android:background="@drawable/ic_logo"
/>
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:id="@+id/text_field_boxes"
@ -34,16 +43,18 @@
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
app:errorColor="@color/A400red"
app:errorColor="@color/nc_white_color_complete"
app:helperText=" "
app:primaryColor="@color/colorPrimary">
app:primaryColor="@color/nc_white_color_complete"
>
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/extended_edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:singleLine="true"/>
android:singleLine="true"
android:textColor="@color/nc_white_color_complete"/>
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
@ -59,7 +70,7 @@
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/padding_between_elements"
android:indeterminate="true"
android:progressTint="@color/colorPrimary"
android:progressTint="@color/nc_white_color"
android:visibility="invisible"/>
</RelativeLayout>

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#0082c9</color>
<color name="colorPrimary">#0082C9</color>
<color name="colorPrimaryDark">#006AA3</color>
<color name="colorAccent">#007CC2</color>
<color name="darkRed">#D32F2F</color>
<color name="nc_darkRed">#D32F2F</color>
<color name="nc_white_color">@color/per70white</color>
<color name="nc_white_color_complete">#FFFFFF</color>
</resources>

View File

@ -7,7 +7,6 @@
<string name="nc_app_name">Nextcloud Talk</string>
<string name="nc_server_product_name">Nextcloud</string>
<color name="nc_background_color">@color/per70white</color>
<string name="nc_push_server_url">https://push-notifications.nextcloud.com</string>
<!-- Will not be shown if empty -->

View File

@ -1,4 +1,4 @@
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">