Prechádzať zdrojové kódy

Merge pull request #1235 from nextcloud/feature/apiv4/open-public-link

[apiv4] 👤🏷️ Fix API calls for guests
Joas Schilling 4 rokov pred
rodič
commit
20f228a715

+ 8 - 1
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -1132,7 +1132,13 @@ public class CallController extends BaseController {
                                             .subscribeOn(Schedulers.io())
                                             .subscribe();
                                 } catch (IOException exception) {
-                                    Log.e(TAG, "Failed to serialize external signaling server");
+                                    Log.e(TAG, "Failed to serialize external signaling server", exception);
+                                }
+                            } else {
+                                try {
+                                    conversationUser.setExternalSignalingServer(LoganSquare.serialize(externalSignalingServer));
+                                } catch (IOException exception) {
+                                    Log.e(TAG, "Failed to serialize external signaling server", exception);
                                 }
                             }
 
@@ -1172,6 +1178,7 @@ public class CallController extends BaseController {
 
                     @Override
                     public void onError(Throwable e) {
+                        Log.e(TAG, e.getMessage(), e);
                     }
 
                     @Override

+ 0 - 1
app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java

@@ -201,7 +201,6 @@ public class CallNotificationController extends BaseController {
     private void proceedToCall() {
         originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken());
         originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
-        originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
 
         getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
                                                  .popChangeHandler(new HorizontalChangeHandler())

+ 12 - 21
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt

@@ -454,8 +454,17 @@ class ChatController(args: Bundle) :
                 R.layout.item_date_header, this
             )
 
+            var senderId = ""
+            if (!conversationUser?.userId.equals("?")) {
+                senderId = "users/" + conversationUser?.userId
+            } else {
+                senderId = currentConversation?.getActorType() + "/" + currentConversation?.getActorId()
+            }
+
+            Log.d(TAG, "Initialize TalkMessagesListAdapter with senderId: " + senderId)
+
             adapter = TalkMessagesListAdapter(
-                conversationUser?.userId,
+                senderId,
                 messageHolders,
                 ImageLoader { imageView, url, payload ->
                     val draweeController = Fresco.newDraweeControllerBuilder()
@@ -1050,18 +1059,6 @@ class ChatController(args: Bundle) :
             })
     }
 
-    private fun setSenderId() {
-        try {
-            val senderId = adapter?.javaClass?.getDeclaredField("senderId")
-            senderId?.isAccessible = true
-            senderId?.set(adapter, conversationUser?.userId)
-        } catch (e: NoSuchFieldException) {
-            Log.w(TAG, "Failed to set sender id")
-        } catch (e: IllegalAccessException) {
-            Log.w(TAG, "Failed to access and set field")
-        }
-    }
-
     private fun submitMessage() {
         if (messageInput != null) {
             val editable = messageInput!!.editableText
@@ -1351,14 +1348,6 @@ class ChatController(args: Bundle) :
                     chatMessage.activeUser = conversationUser
                     chatMessage.isLinkPreviewAllowed = isLinkPreviewAllowed
 
-                    // if credentials are empty, we're acting as a guest
-                    if (TextUtils.isEmpty(credentials) && myFirstMessage != null && !TextUtils.isEmpty(myFirstMessage?.toString())) {
-                        if (chatMessage.actorType == "guests") {
-                            conversationUser?.userId = chatMessage.actorId
-                            setSenderId()
-                        }
-                    }
-
                     val shouldScroll =
                         !isThereANewNotice && !shouldAddNewMessagesNotice && layoutManager?.findFirstVisibleItemPosition() == 0 || adapter != null && adapter?.itemCount == 0
 
@@ -1450,6 +1439,8 @@ class ChatController(args: Bundle) :
         inflater.inflate(R.menu.menu_conversation, menu)
         if (conversationUser?.userId == "?") {
             menu.removeItem(R.id.conversation_info)
+            conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)
+            conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call)
         } else {
             conversationInfoMenuItem = menu.findItem(R.id.conversation_info)
             conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)

+ 305 - 284
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java

@@ -20,24 +20,21 @@
 
 package com.nextcloud.talk.controllers.bottomsheet;
 
-import android.app.Activity;
+import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
@@ -58,6 +55,7 @@ import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.ConductorRemapping;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.NoSupportedApiException;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
@@ -81,6 +79,8 @@ import retrofit2.HttpException;
 @AutoInjector(NextcloudTalkApplication.class)
 public class OperationsMenuController extends BaseController {
 
+    private static final String TAG = "OperationsMenuController";
+
     @BindView(R.id.progress_bar)
     ProgressBar progressBar;
 
@@ -165,13 +165,7 @@ public class OperationsMenuController extends BaseController {
         super.onViewBound(view);
         NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
 
-        processOperation();
-    }
-
-    private void processOperation() {
         currentUser = userUtils.getCurrentUser();
-        OperationsObserver operationsObserver = new OperationsObserver();
-
         if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
             conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1);
             if (callUrl.contains("/index.php")) {
@@ -181,125 +175,182 @@ public class OperationsMenuController extends BaseController {
             }
         }
 
-        if (currentUser != null) {
-            credentials = ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken());
-
-            int apiVersion;
-            if (!TextUtils.isEmpty(baseUrl) && !baseUrl.equals(currentUser.getBaseUrl())) {
-                credentials = null;
-                // FIXME joining a public link we need to check other capabilities
-                apiVersion = 1;
+        if (!TextUtils.isEmpty(baseUrl) && !baseUrl.equals(currentUser.getBaseUrl())) {
+            if (serverCapabilities != null) {
+                try {
+                    useBundledCapabilitiesForGuest();
+                } catch (IOException e) {
+                    // Fall back to fetching capabilities again
+                    fetchCapabilitiesForGuest();
+                }
             } else {
-                apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
+                fetchCapabilitiesForGuest();
             }
+        } else {
+            processOperation();
+        }
+    }
 
 
-            switch (operationCode) {
-                case 2:
-                    ncApi.renameRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
-                                                                         conversation.getToken()),
-                            conversation.getName())
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(operationsObserver);
-                    break;
-                case 3:
-                    ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(),
-                                                                                   conversation.getToken()))
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(operationsObserver);
-                    break;
-                case 4:
-                case 5:
-                case 6:
-                    String pass = "";
-                    if (conversation.getPassword() != null) {
-                        pass = conversation.getPassword();
-                    }
-                    ncApi.setPassword(credentials, ApiUtils.getUrlForRoomPassword(apiVersion, currentUser.getBaseUrl(),
-                                                                                  conversation.getToken()), pass)
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(operationsObserver);
-                    break;
-                case 7:
-                    // Operation 7 is sharing, so we handle this differently
-                    break;
-                case 8:
-                    ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomPublic(apiVersion,
-                                                                                    currentUser.getBaseUrl(),
-                                                                                    conversation.getToken()))
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(operationsObserver);
-                    break;
-                case 10:
-                    ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken))
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(new Observer<RoomOverall>() {
-                                @Override
-                                public void onSubscribe(Disposable d) {
-                                    disposable = d;
-                                }
+    @SuppressLint("LongLogTag")
+    private void useBundledCapabilitiesForGuest() throws IOException {
+        currentUser = new UserEntity();
+        currentUser.setBaseUrl(baseUrl);
+        currentUser.setUserId("?");
+        try {
+            currentUser.setCapabilities(LoganSquare.serialize(serverCapabilities));
+        } catch (IOException e) {
+            Log.e("OperationsMenu", "Failed to serialize capabilities");
+            throw e;
+        }
 
-                                @Override
-                                public void onNext(RoomOverall roomOverall) {
-                                    conversation = roomOverall.getOcs().getData();
-                                    fetchCapabilities(credentials);
-                                }
+        try {
+            checkCapabilities(currentUser);
+            processOperation();
+        } catch (NoSupportedApiException e) {
+            showResultImage(false, false);
+            Log.d(TAG, "No supported server version found", e);
+        }
+    }
 
-                                @Override
-                                public void onError(Throwable e) {
-                                    showResultImage(false, false);
-                                    dispose();
-                                }
+    @SuppressLint("LongLogTag")
+    private void fetchCapabilitiesForGuest() {
+        ncApi.getCapabilities(null, ApiUtils.getUrlForCapabilities(baseUrl))
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Observer<CapabilitiesOverall>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+                    }
 
-                                @Override
-                                public void onComplete() {
-                                    dispose();
-                                }
-                            });
-                    break;
-                case 11:
-                    RetrofitBucket retrofitBucket;
-                    String invite = null;
+                    @SuppressLint("LongLogTag")
+                    @Override
+                    public void onNext(CapabilitiesOverall capabilitiesOverall) {
+                        currentUser = new UserEntity();
+                        currentUser.setBaseUrl(baseUrl);
+                        currentUser.setUserId("?");
+                        try {
+                            currentUser.setCapabilities(LoganSquare.serialize(capabilitiesOverall.getOcs().getData().getCapabilities()));
+                        } catch (IOException e) {
+                            Log.e("OperationsMenu", "Failed to serialize capabilities");
+                        }
 
-                    if (invitedGroups.size() > 0) {
-                        invite = invitedGroups.get(0);
+                        try {
+                            checkCapabilities(currentUser);
+                            processOperation();
+                        } catch (NoSupportedApiException e) {
+                            showResultImage(false, false);
+                            Log.d(TAG, "No supported server version found", e);
+                        }
                     }
 
-                    if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL)) {
-                        retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
-                                                                                 "3", invite, conversationName);
-                    } else {
-                        retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
-                                                                                 "2", invite, conversationName);
+                    @SuppressLint("LongLogTag")
+                    @Override
+                    public void onError(Throwable e) {
+                        showResultImage(false, false);
+                        Log.e(TAG, "Error fetching capabilities for guest", e);
                     }
 
-                    ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
-                            .subscribeOn(Schedulers.io())
-                            .observeOn(AndroidSchedulers.mainThread())
-                            .retry(1)
-                            .subscribe(new Observer<RoomOverall>() {
-                                @Override
-                                public void onSubscribe(Disposable d) {
+                    @Override
+                    public void onComplete() {
 
-                                }
+                    }
+                });
+    }
 
-                                @Override
-                                public void onNext(RoomOverall roomOverall) {
-                                    conversation = roomOverall.getOcs().getData();
+    @SuppressLint("LongLogTag")
+    private void processOperation() {
+        OperationsObserver operationsObserver = new OperationsObserver();
+
+        if (currentUser == null) {
+            showResultImage(false, true);
+            Log.e(TAG, "Ended up in processOperation without a valid currentUser");
+            return;
+        }
 
-                                    ncApi.getRoom(credentials,
-                                            ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
-                                                             conversation.getToken()))
+        credentials = ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken());
+        int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
+
+        switch (operationCode) {
+            case 2:
+                ncApi.renameRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
+                                                                     conversation.getToken()),
+                        conversation.getName())
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(operationsObserver);
+                break;
+            case 3:
+                ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(),
+                                                                               conversation.getToken()))
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(operationsObserver);
+                break;
+            case 4:
+            case 5:
+            case 6:
+                String pass = "";
+                if (conversation.getPassword() != null) {
+                    pass = conversation.getPassword();
+                }
+                ncApi.setPassword(credentials, ApiUtils.getUrlForRoomPassword(apiVersion, currentUser.getBaseUrl(),
+                                                                              conversation.getToken()), pass)
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(operationsObserver);
+                break;
+            case 7:
+                // Operation 7 is sharing, so we handle this differently
+                break;
+            case 8:
+                ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomPublic(apiVersion,
+                                                                                currentUser.getBaseUrl(),
+                                                                                conversation.getToken()))
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(operationsObserver);
+                break;
+            case 10:
+                ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken))
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(new Observer<RoomOverall>() {
+                            @Override
+                            public void onSubscribe(Disposable d) {
+                                disposable = d;
+                            }
+
+                            @Override
+                            public void onNext(RoomOverall roomOverall) {
+                                conversation = roomOverall.getOcs().getData();
+                                if (conversation.isHasPassword() && conversation.isGuest()) {
+                                    eventBus.post(new BottomSheetLockEvent(true, 0,
+                                                                           true, false));
+                                    Bundle bundle = new Bundle();
+                                    bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
+                                    bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl);
+                                    try {
+                                        bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(),
+                                                             Parcels.wrap(LoganSquare.parse(currentUser.getCapabilities(),
+                                                                                            Capabilities.class)));
+                                    } catch (IOException e) {
+                                        Log.e(TAG, "Failed to parse capabilities for guest");
+                                        showResultImage(false, false);
+                                    }
+                                    bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99);
+                                    getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle))
+                                                                       .pushChangeHandler(new HorizontalChangeHandler())
+                                                                       .popChangeHandler(new HorizontalChangeHandler()));
+                                } else if (conversation.isGuest()) {
+                                    ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion,
+                                                                                                     baseUrl,
+                                                                                                     conversationToken), null)
                                             .subscribeOn(Schedulers.io())
                                             .observeOn(AndroidSchedulers.mainThread())
                                             .subscribe(new Observer<RoomOverall>() {
@@ -311,7 +362,7 @@ public class OperationsMenuController extends BaseController {
                                                 @Override
                                                 public void onNext(RoomOverall roomOverall) {
                                                     conversation = roomOverall.getOcs().getData();
-                                                    inviteUsersToAConversation();
+                                                    initiateConversation(false);
                                                 }
 
                                                 @Override
@@ -325,57 +376,131 @@ public class OperationsMenuController extends BaseController {
 
                                                 }
                                             });
-
+                                } else {
+                                    initiateConversation(false);
                                 }
+                            }
 
-                                @Override
-                                public void onError(Throwable e) {
-                                    showResultImage(false, false);
-                                    dispose();
-                                }
+                            @Override
+                            public void onError(Throwable e) {
+                                showResultImage(false, false);
+                                dispose();
+                            }
 
-                                @Override
-                                public void onComplete() {
-                                    dispose();
-                                }
-                            });
+                            @Override
+                            public void onComplete() {
+                                dispose();
+                            }
+                        });
+                break;
+            case 11:
+                RetrofitBucket retrofitBucket;
+                String invite = null;
 
-                    break;
-                case 97:
-                case 98:
-                    if (operationCode == 97) {
-                        ncApi.removeConversationFromFavorites(credentials,
-                                                              ApiUtils.getUrlForRoomFavorite(apiVersion,
-                                                                                             currentUser.getBaseUrl(),
-                                                                                             conversation.getToken()))
-                                .subscribeOn(Schedulers.io())
-                                .observeOn(AndroidSchedulers.mainThread())
-                                .retry(1)
-                                .subscribe(operationsObserver);
-                    } else {
-                        ncApi.addConversationToFavorites(credentials,
-                                                         ApiUtils.getUrlForRoomFavorite(apiVersion,
-                                                                                        currentUser.getBaseUrl(),
-                                                                                        conversation.getToken()))
-                                .subscribeOn(Schedulers.io())
-                                .observeOn(AndroidSchedulers.mainThread())
-                                .retry(1)
-                                .subscribe(operationsObserver);
-                    }
-                    break;
-                case 99:
-                    ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion,
-                                                                                     baseUrl,
-                                                                                     conversationToken),
-                            callPassword)
+                if (invitedGroups.size() > 0) {
+                    invite = invitedGroups.get(0);
+                }
+
+                if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL)) {
+                    retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
+                                                                             "3", invite, conversationName);
+                } else {
+                    retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
+                                                                             "2", invite, conversationName);
+                }
+
+                ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(new Observer<RoomOverall>() {
+                            @Override
+                            public void onSubscribe(Disposable d) {
+
+                            }
+
+                            @Override
+                            public void onNext(RoomOverall roomOverall) {
+                                conversation = roomOverall.getOcs().getData();
+
+                                ncApi.getRoom(credentials,
+                                        ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
+                                                         conversation.getToken()))
+                                        .subscribeOn(Schedulers.io())
+                                        .observeOn(AndroidSchedulers.mainThread())
+                                        .subscribe(new Observer<RoomOverall>() {
+                                            @Override
+                                            public void onSubscribe(Disposable d) {
+
+                                            }
+
+                                            @Override
+                                            public void onNext(RoomOverall roomOverall) {
+                                                conversation = roomOverall.getOcs().getData();
+                                                inviteUsersToAConversation();
+                                            }
+
+                                            @Override
+                                            public void onError(Throwable e) {
+                                                showResultImage(false, false);
+                                                dispose();
+                                            }
+
+                                            @Override
+                                            public void onComplete() {
+
+                                            }
+                                        });
+
+                            }
+
+                            @Override
+                            public void onError(Throwable e) {
+                                showResultImage(false, false);
+                                dispose();
+                            }
+
+                            @Override
+                            public void onComplete() {
+                                dispose();
+                            }
+                        });
+
+                break;
+            case 97:
+            case 98:
+                if (operationCode == 97) {
+                    ncApi.removeConversationFromFavorites(credentials,
+                                                          ApiUtils.getUrlForRoomFavorite(apiVersion,
+                                                                                         currentUser.getBaseUrl(),
+                                                                                         conversation.getToken()))
                             .subscribeOn(Schedulers.io())
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
                             .subscribe(operationsObserver);
-                    break;
-                default:
-                    break;
-            }
+                } else {
+                    ncApi.addConversationToFavorites(credentials,
+                                                     ApiUtils.getUrlForRoomFavorite(apiVersion,
+                                                                                    currentUser.getBaseUrl(),
+                                                                                    conversation.getToken()))
+                            .subscribeOn(Schedulers.io())
+                            .observeOn(AndroidSchedulers.mainThread())
+                            .retry(1)
+                            .subscribe(operationsObserver);
+                }
+                break;
+            case 99:
+                ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion,
+                                                                                 baseUrl,
+                                                                                 conversationToken),
+                        callPassword)
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .retry(1)
+                        .subscribe(operationsObserver);
+                break;
+            default:
+                break;
         }
     }
 
@@ -436,58 +561,11 @@ public class OperationsMenuController extends BaseController {
         dispose();
     }
 
-    private void fetchCapabilities(String credentials) {
-        ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(new Observer<CapabilitiesOverall>() {
-                    @Override
-                    public void onSubscribe(Disposable d) {
-
-                    }
-
-                    @Override
-                    public void onNext(CapabilitiesOverall capabilitiesOverall) {
-                        // Guest checking the capabilities so there is no global server EOL warning until here.
-                        // FIXME check the serverEOL capabilities instead
-                        if (capabilitiesOverall.getOcs().getData()
-                                .getCapabilities().getSpreedCapability() != null &&
-                                capabilitiesOverall.getOcs().getData()
-                                        .getCapabilities().getSpreedCapability()
-                                        .getFeatures() != null && capabilitiesOverall.getOcs().getData()
-                                .getCapabilities().getSpreedCapability()
-                                .getFeatures().contains("chat-v2")) {
-                            if (conversation.isHasPassword() && conversation.isGuest()) {
-                                eventBus.post(new BottomSheetLockEvent(true, 0,
-                                        true, false));
-                                Bundle bundle = new Bundle();
-                                bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
-                                bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl);
-                                bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(),
-                                        Parcels.wrap(capabilitiesOverall.getOcs().getData().getCapabilities()));
-                                bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99);
-                                getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle))
-                                        .pushChangeHandler(new HorizontalChangeHandler())
-                                        .popChangeHandler(new HorizontalChangeHandler()));
-                            } else {
-                                initiateConversation(false, capabilitiesOverall.getOcs().getData()
-                                        .getCapabilities());
-                            }
-                        } else {
-                            showResultImage(false, true);
-                        }
-                    }
-
-                    @Override
-                    public void onError(Throwable e) {
-                        showResultImage(false, false);
-                    }
-
-                    @Override
-                    public void onComplete() {
-
-                    }
-                });
+    private void checkCapabilities(UserEntity currentUser) throws NoSupportedApiException {
+        ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
+        ApiUtils.getCallApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
+        ApiUtils.getChatApiVersion(currentUser, new int[] {1});
+        ApiUtils.getSignalingApiVersion(currentUser, new int[] {2, 1});
     }
 
     private void inviteUsersToAConversation() {
@@ -535,7 +613,7 @@ public class OperationsMenuController extends BaseController {
                                     }
 
                                     if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
-                                        initiateConversation(true, null);
+                                        initiateConversation(true);
                                     }
                                     dispose();
                                 }
@@ -577,95 +655,36 @@ public class OperationsMenuController extends BaseController {
                                 }
 
                                 if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
-                                    initiateConversation(true, null);
+                                    initiateConversation(true);
                                 }
                                 dispose();
                             }
                         });
             }
         } else {
-            initiateConversation(true, null);
+            initiateConversation(true);
         }
     }
 
-    private void initiateConversation(boolean dismissView, @Nullable Capabilities capabilities) {
-        Bundle bundle = new Bundle();
-        boolean isGuestUser = false;
-        boolean hasChatCapability;
-
-        if (baseUrl != null && !baseUrl.equals(currentUser.getBaseUrl())) {
-            isGuestUser = true;
-            // Guest checking the capabilities so there is no global server EOL warning until here.
-            // FIXME check the serverEOL capabilities instead
-            hasChatCapability = capabilities != null && capabilities.getSpreedCapability() != null && capabilities.getSpreedCapability().getFeatures() != null && capabilities.getSpreedCapability().getFeatures().contains("chat-v2");
-        } else {
-            hasChatCapability = currentUser.hasSpreedFeatureCapability("chat-v2");
-        }
-
-
-        if (hasChatCapability) {
-            eventBus.post(new BottomSheetLockEvent(true, 0,
-                    true, true, dismissView));
-
-            Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class);
-            bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken());
-            bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId());
-            bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), conversation.getDisplayName());
-            UserEntity conversationUser;
-            if (isGuestUser) {
-                conversationUser = new UserEntity();
-                conversationUser.setBaseUrl(baseUrl);
-                conversationUser.setUserId("?");
-                try {
-                    conversationUser.setCapabilities(LoganSquare.serialize(capabilities));
-                } catch (IOException e) {
-                    Log.e("OperationsMenu", "Failed to serialize capabilities");
-                }
-            } else {
-                conversationUser = currentUser;
-            }
+    private void initiateConversation(boolean dismissView) {
+        eventBus.post(new BottomSheetLockEvent(true, 0,
+                                               true, true, dismissView));
 
-            bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), conversationUser);
-            bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation));
-            bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword);
-
-            conversationIntent.putExtras(bundle);
-
-            if (getParentController() != null) {
-                ConductorRemapping.INSTANCE.remapChatController(getParentController().getRouter(), conversationUser.getId(),
-                        conversation.getToken(), bundle, true);
-            }
-        } else {
-            initiateCall();
-        }
-    }
-
-
-    private void initiateCall() {
-        eventBus.post(new BottomSheetLockEvent(true, 0, true, true));
+        Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class);
         Bundle bundle = new Bundle();
         bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken());
+        bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId());
+        bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), conversation.getDisplayName());
         bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser);
-        if (baseUrl != null && !baseUrl.equals(currentUser.getBaseUrl())) {
-            bundle.putString(BundleKeys.INSTANCE.getKEY_MODIFIED_BASE_URL(), baseUrl);
-        }
         bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation));
+        bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword);
 
-        if (getActivity() != null) {
-
-            Intent callIntent = new Intent(getActivity(), MagicCallActivity.class);
-            callIntent.putExtras(bundle);
-
-            InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
-            if (imm != null) {
-                imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
-            }
-
-            new Handler().postDelayed(() -> getParentController().getRouter().popCurrentController(), 100);
-            startActivity(callIntent);
+        conversationIntent.putExtras(bundle);
 
+        if (getParentController() != null) {
+            ConductorRemapping.INSTANCE.remapChatController(getParentController().getRouter(), currentUser.getId(),
+                                                            conversation.getToken(), bundle, true);
         }
-
     }
 
     private class OperationsObserver implements Observer {
@@ -678,11 +697,13 @@ public class OperationsMenuController extends BaseController {
         @Override
         public void onNext(Object o) {
             if (operationCode != 99) {
+                RoomOverall roomOverall = (RoomOverall) o;
+                conversation = roomOverall.getOcs().getData();
                 showResultImage(true, false);
             } else {
                 RoomOverall roomOverall = (RoomOverall) o;
                 conversation = roomOverall.getOcs().getData();
-                initiateConversation(true, serverCapabilities);
+                initiateConversation(true);
             }
         }
 

+ 6 - 2
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java

@@ -214,12 +214,16 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
         return new IUser() {
             @Override
             public String getId() {
-                return actorId;
+                return actorType + "/" + actorId;
             }
 
             @Override
             public String getName() {
-                return actorDisplayName;
+                if (!TextUtils.isEmpty(actorDisplayName)) {
+                    return actorDisplayName;
+                }
+
+                return NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest);
             }
 
             @Override

+ 30 - 0
app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.java

@@ -61,6 +61,10 @@ public class Conversation {
     public boolean hasPassword;
     @JsonField(name = "sessionId")
     public String sessionId;
+    @JsonField(name = "actorId")
+    public String actorId;
+    @JsonField(name = "actorType")
+    public String actorType;
     public String password;
     @JsonField(name = "isFavorite")
     public boolean isFavorite;
@@ -180,6 +184,14 @@ public class Conversation {
         return this.participantType;
     }
 
+    public String getActorId() {
+        return actorId;
+    }
+
+    public String getActorType() {
+        return actorType;
+    }
+
     public boolean isHasPassword() {
         return this.hasPassword;
     }
@@ -277,6 +289,14 @@ public class Conversation {
         this.participantType = participantType;
     }
 
+    public void setActorId(String actorId) {
+        this.actorId = actorId;
+    }
+
+    public void setActorType(String actorType) {
+        this.actorType = actorType;
+    }
+
     public void setHasPassword(boolean hasPassword) {
         this.hasPassword = hasPassword;
     }
@@ -399,6 +419,12 @@ public class Conversation {
         if (sessionId != null ? !sessionId.equals(that.sessionId) : that.sessionId != null) {
             return false;
         }
+        if (actorId != null ? !actorId.equals(that.actorId) : that.actorId != null) {
+            return false;
+        }
+        if (actorType != null ? !actorType.equals(that.actorType) : that.actorType != null) {
+            return false;
+        }
         if (password != null ? !password.equals(that.password) : that.password != null) {
             return false;
         }
@@ -441,6 +467,8 @@ public class Conversation {
         result = 31 * result + (int) (lastPing ^ (lastPing >>> 32));
         result = 31 * result + (participants != null ? participants.hashCode() : 0);
         result = 31 * result + (participantType != null ? participantType.hashCode() : 0);
+        result = 31 * result + (actorId != null ? actorId.hashCode() : 0);
+        result = 31 * result + (actorType != null ? actorType.hashCode() : 0);
         result = 31 * result + (hasPassword ? 1 : 0);
         result = 31 * result + (sessionId != null ? sessionId.hashCode() : 0);
         result = 31 * result + (password != null ? password.hashCode() : 0);
@@ -473,6 +501,8 @@ public class Conversation {
                 ", lastPing=" + lastPing +
                 ", participants=" + participants +
                 ", participantType=" + participantType +
+                ", actorId=" + actorId +
+                ", actorType=" + actorType +
                 ", hasPassword=" + hasPassword +
                 ", sessionId='" + sessionId + '\'' +
                 ", password='" + password + '\'' +

+ 6 - 4
app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java

@@ -152,9 +152,10 @@ public class MagicWebSocketInstance extends WebSocketListener {
     public void restartWebSocket() {
         reconnecting = true;
 
-            Request request = new Request.Builder().url(connectionUrl).build();
-            okHttpClient.newWebSocket(request, this);
-            restartCount++;
+        Log.d(TAG, "restartWebSocket: " + connectionUrl);
+        Request request = new Request.Builder().url(connectionUrl).build();
+        okHttpClient.newWebSocket(request, this);
+        restartCount++;
     }
 
     @Override
@@ -196,6 +197,7 @@ public class MagicWebSocketInstance extends WebSocketListener {
                         eventBus.post(new WebSocketCommunicationEvent("hello", helloHasHap));
                         break;
                     case "error":
+                        Log.e(TAG, "Received error: " + text);
                         ErrorOverallWebSocketMessage errorOverallWebSocketMessage = LoganSquare.parse(text, ErrorOverallWebSocketMessage.class);
                         if (("no_such_session").equals(errorOverallWebSocketMessage.getErrorWebSocketMessage().getCode())) {
                             LoggingUtils.INSTANCE.writeLogEntryToFile(context,
@@ -351,7 +353,7 @@ public class MagicWebSocketInstance extends WebSocketListener {
                 }
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            Log.e(TAG, e.getMessage(), e);
         }
     }
 

+ 3 - 1
app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java

@@ -98,7 +98,9 @@ public class WebSocketConnectionHelper {
         authWebSocketMessage.setUrl(ApiUtils.getUrlForSignalingBackend(apiVersion, userEntity.getBaseUrl()));
         AuthParametersWebSocketMessage authParametersWebSocketMessage = new AuthParametersWebSocketMessage();
         authParametersWebSocketMessage.setTicket(ticket);
-        authParametersWebSocketMessage.setUserid(userEntity.getUserId());
+        if (!userEntity.getUserId().equals("?")) {
+            authParametersWebSocketMessage.setUserid(userEntity.getUserId());
+        }
         authWebSocketMessage.setAuthParametersWebSocketMessage(authParametersWebSocketMessage);
         helloWebSocketMessage.setAuthWebSocketMessage(authWebSocketMessage);
         helloOverallWebSocketMessage.setHelloWebSocketMessage(helloWebSocketMessage);