Selaa lähdekoodia

Work on #78

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 7 vuotta sitten
vanhempi
commit
a0b30abb1f
18 muutettua tiedostoa jossa 263 lisäystä ja 147 poistoa
  1. 93 83
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.java
  2. 2 1
      app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java
  3. 2 1
      app/src/main/java/com/nextcloud/talk/adapters/items/AppItem.java
  4. 6 2
      app/src/main/java/com/nextcloud/talk/api/NcApi.java
  5. 38 18
      app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java
  6. 1 1
      app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java
  7. 11 11
      app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java
  8. 3 6
      app/src/main/java/com/nextcloud/talk/controllers/base/bottomnavigation/BottomNavigationController.java
  9. 2 2
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java
  10. 35 4
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java
  11. 56 10
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java
  12. 5 3
      app/src/main/java/com/nextcloud/talk/events/BottomSheetLockEvent.java
  13. 2 1
      app/src/main/java/com/nextcloud/talk/models/ImportAccount.java
  14. 1 1
      app/src/main/java/com/nextcloud/talk/utils/ErrorMessageHolder.java
  15. 2 2
      app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java
  16. 2 0
      app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java
  17. 1 1
      app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java
  18. 1 0
      app/src/main/res/values/strings.xml

+ 93 - 83
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -76,6 +76,7 @@ import com.nextcloud.talk.events.PeerConnectionEvent;
 import com.nextcloud.talk.events.SessionDescriptionSendEvent;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 import com.nextcloud.talk.utils.animations.PulseAnimation;
+import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.webrtc.MagicAudioManager;
 import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
@@ -242,7 +243,7 @@ public class CallActivity extends AppCompatActivity {
 
         roomToken = getIntent().getExtras().getString("roomToken", "");
         userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable("userEntity"));
-        callSession = "0";
+        callSession = getIntent().getExtras().getString(BundleKeys.KEY_CALL_SESSION, "0");
         credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
 
         networkBroadcastReceier = new BroadcastReceiver() {
@@ -774,121 +775,130 @@ public class CallActivity extends AppCompatActivity {
     }
 
     private void joinRoomAndCall() {
-        ncApi.joinRoom(credentials, ApiHelper.getUrlForRoomParticipants(userEntity.getBaseUrl(), roomToken))
+        if (callSession.equals("0")) {
+            ncApi.joinRoom(credentials, ApiHelper.getUrlForRoomParticipants(userEntity.getBaseUrl(), roomToken), null)
+                    .subscribeOn(Schedulers.newThread())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .retry(3)
+                    .subscribe(new Observer<CallOverall>() {
+                        @Override
+                        public void onSubscribe(Disposable d) {
+
+                        }
+
+                        @Override
+                        public void onNext(CallOverall callOverall) {
+                            performCall(callOverall.getOcs().getData().getSessionId());
+                        }
+
+                        @Override
+                        public void onError(Throwable e) {
+
+                        }
+
+                        @Override
+                        public void onComplete() {
+
+                        }
+                    });
+        } else {
+            performCall(null);
+        }
+    }
+
+    private void performCall(@Nullable String callSessionId) {
+        ncApi.joinCall(credentials,
+                ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken))
                 .subscribeOn(Schedulers.newThread())
-                .observeOn(AndroidSchedulers.mainThread())
                 .retry(3)
-                .subscribe(new Observer<CallOverall>() {
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Observer<GenericOverall>() {
                     @Override
                     public void onSubscribe(Disposable d) {
 
                     }
 
                     @Override
-                    public void onNext(CallOverall callOverall) {
-                        ncApi.joinCall(credentials,
-                                ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken))
+                    public void onNext(GenericOverall genericOverall) {
+                        inCall = true;
+                        if (callSessionId != null) {
+                            callSession = callSessionId;
+                        }
+
+                        // start pinging the call
+                        ncApi.pingCall(ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
+                                ApiHelper.getUrlForCallPing(userEntity.getBaseUrl(), roomToken))
                                 .subscribeOn(Schedulers.newThread())
-                                .retry(3)
                                 .observeOn(AndroidSchedulers.mainThread())
+                                .repeatWhen(observable -> observable.delay(5000, TimeUnit.MILLISECONDS))
+                                .takeWhile(observable -> inCall)
+                                .retry(3, observable -> inCall)
                                 .subscribe(new Observer<GenericOverall>() {
                                     @Override
                                     public void onSubscribe(Disposable d) {
-
+                                        pingDisposable = d;
                                     }
 
                                     @Override
                                     public void onNext(GenericOverall genericOverall) {
-                                        inCall = true;
-
-                                        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))
-                                                .takeWhile(observable -> inCall)
-                                                .retry(3, observable -> inCall)
-                                                .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)
-                                                .takeWhile(observable -> inCall)
-                                                .retry(3, observable -> inCall)
-                                                .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) {
-                                                                    Log.e(TAG, "Failed to process received signaling" +
-                                                                            " message");
-                                                                }
-                                                            }
-                                                        }
-                                                    }
-
-                                                    @Override
-                                                    public void onError(Throwable e) {
-                                                        dispose(signalingDisposable);
-                                                    }
-
-                                                    @Override
-                                                    public void onComplete() {
-                                                        dispose(signalingDisposable);
-                                                    }
-                                                });
-
 
                                     }
 
                                     @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)
+                                .takeWhile(observable -> inCall)
+                                .retry(3, observable -> inCall)
+                                .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) {
+                                                    Log.e(TAG, "Failed to process received signaling" +
+                                                            " message");
+                                                }
+                                            }
+                                        }
+                                    }
 
+                                    @Override
+                                    public void onError(Throwable e) {
+                                        dispose(signalingDisposable);
+                                    }
+
+                                    @Override
+                                    public void onComplete() {
+                                        dispose(signalingDisposable);
                                     }
                                 });
+
+
                     }
 
                     @Override
                     public void onError(Throwable e) {
-
                     }
 
                     @Override

+ 2 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java

@@ -57,7 +57,8 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
 
     private Participant participant;
     private UserEntity userEntity;
-    @Nullable private Account account;
+    @Nullable
+    private Account account;
 
     public AdvancedUserItem(Participant participant, UserEntity userEntity, @Nullable Account account) {
         this.participant = participant;

+ 2 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/AppItem.java

@@ -44,7 +44,8 @@ public class AppItem extends AbstractFlexibleItem<AppItem.AppItemViewHolder> {
     private String title;
     private String packageName;
     private String name;
-    @Nullable private Drawable drawable;
+    @Nullable
+    private Drawable drawable;
 
     public AppItem(String title, String packageName, String name, @Nullable Drawable drawable) {
         this.title = title;

+ 6 - 2
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -20,6 +20,8 @@
  */
 package com.nextcloud.talk.api;
 
+import android.support.annotation.Nullable;
+
 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.generic.Status;
@@ -97,7 +99,7 @@ public interface NcApi {
     @FormUrlEncoded
     @PUT
     Observable<GenericOverall> renameRoom(@Header("Authorization") String authorization, @Url String url,
-                                @Field("roomName") String roomName);
+                                          @Field("roomName") String roomName);
 
 
     /*
@@ -139,8 +141,10 @@ public interface NcApi {
     @GET
     Observable<ParticipantsOverall> getPeersForCall(@Header("Authorization") String authorization, @Url String url);
 
+    @FormUrlEncoded
     @POST
-    Observable<CallOverall> joinRoom(@Header("Authorization") String authorization, @Url String url);
+    Observable<CallOverall> joinRoom(@Header("Authorization") String authorization, @Url String url,
+                                     @Nullable @Field("password") String password);
 
     @DELETE
     Observable<GenericOverall> leaveRoom(@Header("Authorization") String authorization, @Url String url);

+ 38 - 18
app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java

@@ -56,10 +56,12 @@ import com.nextcloud.talk.activities.CallActivity;
 import com.nextcloud.talk.adapters.items.CallItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.helpers.api.ApiHelper;
+import com.nextcloud.talk.api.models.json.participants.Participant;
 import com.nextcloud.talk.api.models.json.rooms.Room;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.controllers.bottomsheet.CallMenuController;
+import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController;
 import com.nextcloud.talk.events.BottomSheetLockEvent;
 import com.nextcloud.talk.events.MoreMenuClickEvent;
 import com.nextcloud.talk.persistence.entities.UserEntity;
@@ -387,14 +389,14 @@ public class CallsListController extends BaseController implements SearchView.On
     @Subscribe(threadMode = ThreadMode.MAIN)
     public void onMessageEvent(BottomSheetLockEvent bottomSheetLockEvent) {
         if (bottomSheet != null) {
-            if (!bottomSheetLockEvent.isCancel()) {
-                bottomSheet.setCancelable(bottomSheetLockEvent.isCancel());
+            if (!bottomSheetLockEvent.isCancelable()) {
+                bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable());
             } else {
                 if (bottomSheetLockEvent.getDelay() != 0 && bottomSheetLockEvent.isShouldRefreshData()) {
                     fetchData(true);
                 } else {
-                    bottomSheet.setCancelable(true);
-                    if (bottomSheet.isShowing()) {
+                    bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable());
+                    if (bottomSheet.isShowing() && bottomSheetLockEvent.isCancel()) {
                         bottomSheet.cancel();
                     }
                 }
@@ -408,35 +410,53 @@ public class CallsListController extends BaseController implements SearchView.On
         Room room = moreMenuClickEvent.getRoom();
         bundleBuilder.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
 
+        prepareAndShowBottomSheetWithBundle(bundleBuilder.build(), true);
+    }
+
+    private void prepareAndShowBottomSheetWithBundle(Bundle bundle, boolean shouldShowCallMenuController) {
         View view = getActivity().getLayoutInflater().inflate(R.layout.bottom_sheet, null, false);
 
-        getChildRouter((ViewGroup) view).setRoot(
-                RouterTransaction.with(new CallMenuController(bundleBuilder.build()))
-                        .popChangeHandler(new HorizontalChangeHandler())
-                        .pushChangeHandler(new HorizontalChangeHandler()));
+        if (shouldShowCallMenuController) {
+            getChildRouter((ViewGroup) view).setRoot(
+                    RouterTransaction.with(new CallMenuController(bundle))
+                            .popChangeHandler(new HorizontalChangeHandler())
+                            .pushChangeHandler(new HorizontalChangeHandler()));
+        } else {
+            getChildRouter((ViewGroup) view).setRoot(
+                    RouterTransaction.with(new EntryMenuController(bundle))
+                            .popChangeHandler(new HorizontalChangeHandler())
+                            .pushChangeHandler(new HorizontalChangeHandler()));
+        }
 
-        if (bottomSheet == null) {
-            bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create();
-            if (bottomSheet.getWindow() != null) {
-                bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-            }
+        bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create();
+        if (bottomSheet.getWindow() != null) {
+            bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
         }
 
         bottomSheet.show();
     }
 
+
     @Override
     public boolean onItemClick(int position) {
-        overridePushHandler(new NoOpControllerChangeHandler());
-        overridePopHandler(new NoOpControllerChangeHandler());
         CallItem callItem = adapter.getItem(position);
         if (callItem != null && getActivity() != null) {
-            Intent callIntent = new Intent(getActivity(), CallActivity.class);
+            Room room = callItem.getModel();
             BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
             bundleBuilder.putString("roomToken", callItem.getModel().getToken());
             bundleBuilder.putParcelable("userEntity", Parcels.wrap(userEntity));
-            callIntent.putExtras(bundleBuilder.build());
-            startActivity(callIntent);
+
+            if (room.hasPassword && (room.participantType.equals(Participant.ParticipantType.GUEST) ||
+                    room.participantType.equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
+                bundleBuilder.putInt(BundleKeys.KEY_OPERATION_CODE, 99);
+                prepareAndShowBottomSheetWithBundle(bundleBuilder.build(), false);
+            } else {
+                overridePushHandler(new NoOpControllerChangeHandler());
+                overridePopHandler(new NoOpControllerChangeHandler());
+                Intent callIntent = new Intent(getActivity(), CallActivity.class);
+                callIntent.putExtras(bundleBuilder.build());
+                startActivity(callIntent);
+            }
         }
 
         return true;

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

@@ -123,7 +123,7 @@ public class ServerSelectionController extends BaseController {
                 });
             } else if (AccountUtils.findAccounts(userUtils.getUsers()).size() > 0) {
                 if (!TextUtils.isEmpty(AccountUtils.getAppNameBasedOnPackage(getResources()
-                                .getString(R.string.nc_import_accounts_from)))) {
+                        .getString(R.string.nc_import_accounts_from)))) {
                     if (AccountUtils.findAccounts(userUtils.getUsers()).size() > 1) {
                         providersTextView.setText(String.format(getResources().getString(R.string
                                 .nc_server_import_accounts), AccountUtils.getAppNameBasedOnPackage(getResources()

+ 11 - 11
app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java

@@ -185,22 +185,22 @@ public class SwitchAccountController extends BaseController {
                 Account account;
                 ImportAccount importAccount;
                 for (Object accountObject : AccountUtils.findAccounts(userUtils.getUsers())) {
-                        account = (Account) accountObject;
-                        importAccount = AccountUtils.getInformationFromAccount(account);
-
-                        participant = new Participant();
-                        participant.setName(importAccount.getUsername());
-                        participant.setUserId(importAccount.getUsername());
-                        userEntity = new UserEntity();
-                        userEntity.setBaseUrl(importAccount.getBaseUrl());
-                        userItems.add(new AdvancedUserItem(participant, userEntity, account));
-                    }
+                    account = (Account) accountObject;
+                    importAccount = AccountUtils.getInformationFromAccount(account);
+
+                    participant = new Participant();
+                    participant.setName(importAccount.getUsername());
+                    participant.setUserId(importAccount.getUsername());
+                    userEntity = new UserEntity();
+                    userEntity.setBaseUrl(importAccount.getBaseUrl());
+                    userItems.add(new AdvancedUserItem(participant, userEntity, account));
+                }
 
                 adapter.addListener(onImportItemClickListener);
                 adapter.updateDataSet(userItems, false);
             }
 
-            }
+        }
 
         prepareViews();
     }

+ 3 - 6
app/src/main/java/com/nextcloud/talk/controllers/base/bottomnavigation/BottomNavigationController.java

@@ -124,12 +124,9 @@ public abstract class BottomNavigationController extends BaseController {
         bottomNavigationView.inflateMenu(getMenuResource());
 
         bottomNavigationView.setOnNavigationItemSelectedListener(
-                new BottomNavigationView.OnNavigationItemSelectedListener() {
-                    @Override
-                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
-                        navigateTo(item.getItemId(), getControllerFor(item.getItemId()));
-                        return true;
-                    }
+                item -> {
+                    navigateTo(item.getItemId(), getControllerFor(item.getItemId()));
+                    return true;
                 });
     }
 

+ 2 - 2
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java

@@ -187,7 +187,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
                 if (tag > 0 && tag < 10) {
                     bundle.putInt(BundleKeys.KEY_OPERATION_CODE, tag);
                     if (tag != 2 && tag != 4 && tag != 6 && tag != 7) {
-                        eventBus.post(new BottomSheetLockEvent(false, 0, false));
+                        eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
                         getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)));
                     } else if (tag != 7) {
                         getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)));
@@ -206,7 +206,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
                     Intent intent = new Intent(shareIntent);
                     intent.setComponent(new ComponentName(appItem.getPackageName(), appItem.getName()));
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    eventBus.post(new BottomSheetLockEvent(true, 0, false));
+                    eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
                     getActivity().startActivity(intent);
                 } else {
                     bundle.putInt(BundleKeys.KEY_OPERATION_CODE, 7);

+ 35 - 4
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java

@@ -39,6 +39,8 @@ import com.nextcloud.talk.api.models.json.rooms.Room;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.events.BottomSheetLockEvent;
+import com.nextcloud.talk.persistence.entities.UserEntity;
+import com.nextcloud.talk.utils.ErrorMessageHolder;
 import com.nextcloud.talk.utils.ShareUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
@@ -97,12 +99,40 @@ public class EntryMenuController extends BaseController {
         return inflater.inflate(R.layout.controller_entry_menu, container, false);
     }
 
+    @Override
+    protected void onAttach(@NonNull View view) {
+        super.onAttach(view);
+        if (ErrorMessageHolder.getInstance().getMessageType() != null &&
+                ErrorMessageHolder.getInstance().getMessageType().equals(ErrorMessageHolder.ErrorMessageType.CALL_PASSWORD_WRONG)) {
+            textFieldBoxes.setError(getResources().getString(R.string.nc_wrong_password), true);
+            ErrorMessageHolder.getInstance().setMessageType(null);
+            if (proceedButton.isEnabled()) {
+                proceedButton.setEnabled(false);
+                proceedButton.setAlpha(0.7f);
+            }
+        }
+    }
+
     @OnClick(R.id.ok_button)
     public void onProceedButtonClick() {
-        if (operationCode != 7) {
-            eventBus.post(new BottomSheetLockEvent(false, 0, false));
+        Bundle bundle;
+        if (operationCode == 99) {
+            eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
+            UserEntity userEntity = userUtils.getCurrentUser();
+
+            if (userEntity != null) {
+                eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
+                bundle = new Bundle();
+                bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+                bundle.putParcelable("userEntity", Parcels.wrap(userEntity));
+                bundle.putString(BundleKeys.KEY_CALL_PASSWORD, editText.getText().toString());
+                getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)));
+            }
+
+        } else if (operationCode != 7) {
+            eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
 
-            Bundle bundle = new Bundle();
+            bundle = new Bundle();
             if (operationCode == 4 || operationCode == 6) {
                 room.setPassword(editText.getText().toString());
             } else {
@@ -119,7 +149,7 @@ public class EntryMenuController extends BaseController {
                 intent.setComponent(new ComponentName(packageName, name));
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 getActivity().startActivity(intent);
-                eventBus.post(new BottomSheetLockEvent(true, 0, false));
+                eventBus.post(new BottomSheetLockEvent(true, 0, false, false));
             }
         }
     }
@@ -190,6 +220,7 @@ public class EntryMenuController extends BaseController {
                 break;
             case 6:
             case 7:
+            case 99:
                 labelText = getResources().getString(R.string.nc_password);
                 break;
             default:

+ 56 - 10
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java

@@ -20,6 +20,7 @@
 
 package com.nextcloud.talk.controllers.bottomsheet;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.view.LayoutInflater;
@@ -30,15 +31,20 @@ import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
 import com.nextcloud.talk.R;
+import com.nextcloud.talk.activities.CallActivity;
 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.rooms.Room;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.events.BottomSheetLockEvent;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 import com.nextcloud.talk.utils.ColorUtils;
+import com.nextcloud.talk.utils.ErrorMessageHolder;
+import com.nextcloud.talk.utils.bundle.BundleBuilder;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 
@@ -53,6 +59,7 @@ import io.reactivex.Observer;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.schedulers.Schedulers;
+import retrofit2.HttpException;
 
 @AutoInjector(NextcloudTalkApplication.class)
 public class OperationsMenuController extends BaseController {
@@ -82,7 +89,11 @@ public class OperationsMenuController extends BaseController {
     private int operationCode;
     private Room room;
 
+    private UserEntity userEntity;
+    private String callPassword;
+
     private Disposable disposable;
+    private Disposable secondaryDisposable;
 
     private int retryCount = 0;
 
@@ -90,6 +101,11 @@ public class OperationsMenuController extends BaseController {
         super(args);
         this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE);
         this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
+
+        this.callPassword = args.getString(BundleKeys.KEY_CALL_PASSWORD, "");
+        if (args.containsKey("userEntity")) {
+            this.userEntity = Parcels.unwrap(args.getParcelable("userEntity"));
+        }
     }
 
     @Override
@@ -166,6 +182,13 @@ public class OperationsMenuController extends BaseController {
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
                             .subscribe(operationsObserver);
+                case 99:
+                    ncApi.joinRoom(credentials, ApiHelper.getUrlForRoomParticipants(userEntity.getBaseUrl(), room.getToken()),
+                            callPassword)
+                            .subscribeOn(Schedulers.newThread())
+                            .observeOn(AndroidSchedulers.mainThread())
+                            .retry(1)
+                            .subscribe(operationsObserver);
                     break;
                 default:
                     break;
@@ -195,11 +218,11 @@ public class OperationsMenuController extends BaseController {
 
         resultsTextView.setVisibility(View.VISIBLE);
         if (everythingOK) {
-            eventBus.post(new BottomSheetLockEvent(true, 2500, true));
+            eventBus.post(new BottomSheetLockEvent(true, 2500, true, true));
         } else {
             resultImageView.setImageDrawable(ColorUtils.getTintedDrawable(getResources(), R.drawable
                     .ic_cancel_black_24dp, R.color.nc_darkRed));
-            okButton.setOnClickListener(v -> eventBus.post(new BottomSheetLockEvent(true, 0, true)));
+            okButton.setOnClickListener(v -> eventBus.post(new BottomSheetLockEvent(true, 0, true, true)));
             okButton.setVisibility(View.VISIBLE);
         }
     }
@@ -212,6 +235,12 @@ public class OperationsMenuController extends BaseController {
         disposable = null;
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        dispose();
+    }
+
     private class OperationsObserver implements Observer {
 
         @Override
@@ -222,13 +251,36 @@ public class OperationsMenuController extends BaseController {
 
         @Override
         public void onNext(Object o) {
-            showResultImage(true);
+            if (operationCode != 99) {
+                showResultImage(true);
+            } else {
+                BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
+                bundleBuilder.putString("roomToken", room.getToken());
+                bundleBuilder.putParcelable("userEntity", Parcels.wrap(userEntity));
+                bundleBuilder.putString(BundleKeys.KEY_CALL_SESSION, ((CallOverall) o).getOcs().getData().getSessionId());
+                overridePushHandler(new NoOpControllerChangeHandler());
+                overridePopHandler(new NoOpControllerChangeHandler());
+                Intent callIntent = new Intent(getActivity(), CallActivity.class);
+                callIntent.putExtras(bundleBuilder.build());
+                startActivity(callIntent);
+            }
         }
 
         @Override
         public void onError(Throwable e) {
             if (retryCount == 1) {
-                showResultImage(false);
+                if (operationCode != 99 || !(e instanceof HttpException)) {
+                    showResultImage(false);
+                } else {
+                    HttpException httpException = (HttpException) e;
+                    if (((HttpException) e).response().code() == 403) {
+                        // just make it cancelable again
+                        ErrorMessageHolder.getInstance().setMessageType(ErrorMessageHolder.ErrorMessageType.CALL_PASSWORD_WRONG);
+                        getRouter().popCurrentController();
+                    } else {
+                        showResultImage(false);
+                    }
+                }
             }
             dispose();
         }
@@ -238,10 +290,4 @@ public class OperationsMenuController extends BaseController {
             dispose();
         }
     }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        dispose();
-    }
 }

+ 5 - 3
app/src/main/java/com/nextcloud/talk/events/BottomSheetLockEvent.java

@@ -24,13 +24,15 @@ import lombok.Data;
 
 @Data
 public class BottomSheetLockEvent {
-    private final boolean cancel;
+    private final boolean cancelable;
     private final int delay;
     private final boolean shouldRefreshData;
+    private final boolean cancel;
 
-    public BottomSheetLockEvent(boolean cancel, int delay, boolean shouldRefreshData) {
-        this.cancel = cancel;
+    public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData, boolean cancel) {
+        this.cancelable = cancelable;
         this.delay = delay;
         this.shouldRefreshData = shouldRefreshData;
+        this.cancel = cancel;
     }
 }

+ 2 - 1
app/src/main/java/com/nextcloud/talk/models/ImportAccount.java

@@ -27,7 +27,8 @@ import lombok.Data;
 @Data
 public class ImportAccount {
     public String username;
-    @Nullable public String token;
+    @Nullable
+    public String token;
     public String baseUrl;
 
     public ImportAccount(String username, @Nullable String token, String baseUrl) {

+ 1 - 1
app/src/main/java/com/nextcloud/talk/utils/ErrorMessageHolder.java

@@ -40,7 +40,7 @@ public class ErrorMessageHolder {
 
     public enum ErrorMessageType {
         WRONG_ACCOUNT, ACCOUNT_UPDATED_NOT_ADDED, ACCOUNT_SCHEDULED_FOR_DELETION, SERVER_WITHOUT_TALK,
-        FAILED_TO_IMPORT_ACCOUNT, ACCOUNT_WAS_IMPORTED
+        FAILED_TO_IMPORT_ACCOUNT, ACCOUNT_WAS_IMPORTED, CALL_PASSWORD_WRONG
     }
 
 

+ 2 - 2
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java

@@ -49,11 +49,11 @@ public class NotificationUtils {
             int usage;
 
             if (channelId.equals(NotificationUtils.NOTIFICATION_CHANNEL_CALLS)) {
-                usage =  AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+                usage = AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
             } else {
                 usage = AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
             }
-            
+
             channel.setSound(soundUri, new AudioAttributes.Builder().setUsage(usage).build());
             channel.setDescription(channelDescription);
             channel.enableLights(vibrate);

+ 2 - 0
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java

@@ -32,4 +32,6 @@ public class BundleKeys {
     public static final String KEY_SHARE_INTENT = "KEY_SHARE_INTENT";
     public static final String KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME";
     public static final String KEY_APP_ITEM_NAME = "KEY_APP_ITEM_NAME";
+    public static final String KEY_CALL_PASSWORD = "KEY_CALL_PASSWORD";
+    public static final String KEY_CALL_SESSION = "KEY_CALL_SESSION";
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

@@ -149,7 +149,7 @@ public class UserUtils {
     }
 
     public Observable<UserEntity> createOrUpdateUser(@Nullable String username, @Nullable String token, @Nullable String
-                                                     serverUrl,
+            serverUrl,
                                                      @Nullable String displayName,
                                                      @Nullable String pushConfigurationState,
                                                      @Nullable Boolean currentUser,

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -61,6 +61,7 @@
     <string name="nc_username">Username</string>
     <string name="nc_password">Password</string>
     <string name="nc_new_password">New password</string>
+    <string name="nc_wrong_password">Wrong password</string>
     <string name="nc_about">About</string>
     <string name="nc_privacy">Privacy</string>
     <string name="nc_get_source_code">Get source code</string>