From 517e74820f55016bafa72148fea67bbec6e46a25 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 20 Feb 2018 18:16:45 +0100 Subject: [PATCH] Some work on group/public calls Signed-off-by: Mario Danic --- .../talk/controllers/ContactsController.java | 49 +++++- .../bottomsheet/EntryMenuController.java | 16 +- .../bottomsheet/OperationsMenuController.java | 149 +++++++++++++++++- .../nextcloud/talk/models/database/User.java | 2 +- .../talk/models/json/rooms/Room.java | 1 + .../nextcloud/talk/utils/AccountUtils.java | 3 +- .../com/nextcloud/talk/utils/ApiUtils.java | 13 +- .../com/nextcloud/talk/utils/DeviceUtils.java | 4 +- .../talk/utils/bundle/BundleKeys.java | 9 +- app/src/main/res/values/strings.xml | 2 +- 10 files changed, 233 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java index 85a51a19a..f9f7545a4 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -42,6 +42,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.LinearLayout; @@ -50,6 +51,7 @@ import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler; +import com.kennyc.bottomsheet.BottomSheet; import com.nextcloud.talk.R; import com.nextcloud.talk.activities.CallActivity; import com.nextcloud.talk.adapters.items.EmptyFooterItem; @@ -59,9 +61,11 @@ import com.nextcloud.talk.adapters.items.UserItem; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; +import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController; import com.nextcloud.talk.models.RetrofitBucket; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.participants.Participant; +import com.nextcloud.talk.models.json.rooms.Room; import com.nextcloud.talk.models.json.rooms.RoomOverall; import com.nextcloud.talk.models.json.sharees.Sharee; import com.nextcloud.talk.models.json.sharees.ShareesOverall; @@ -110,6 +114,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ @Inject NcApi ncApi; + @BindView(R.id.recycler_view) RecyclerView recyclerView; @@ -132,6 +137,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ private Disposable cacheQueryDisposable; private FlexibleAdapter adapter; private List contactItems = new ArrayList<>(); + private BottomSheet bottomSheet; + private View view; private SmoothScrollLinearLayoutManager layoutManager; @@ -232,7 +239,26 @@ public class ContactsController extends BaseController implements SearchView.OnQ @Optional @OnClick(R.id.done_button) public void onDoneButtonClick() { + Bundle bundle = new Bundle(); + Room.RoomType roomType; + if (isPublicCall) { + roomType = Room.RoomType.ROOM_PUBLIC_CALL; + } else { + roomType = Room.RoomType.ROOM_GROUP_CALL; + } + bundle.putParcelable(BundleKeys.KEY_CONVERSATION_TYPE, Parcels.wrap(roomType)); + ArrayList userIds = new ArrayList<>(); + Set selectedPositions = adapter.getSelectedPositionsAsSet(); + for (int selectedPosition : selectedPositions) { + if (adapter.getItem(selectedPosition) instanceof UserItem) { + UserItem userItem = (UserItem) adapter.getItem(selectedPosition); + userIds.add(userItem.getModel().getUserId()); + } + } + bundle.putStringArrayList(BundleKeys.KEY_INVITED_PARTICIPANTS, userIds); + bundle.putInt(BundleKeys.KEY_OPERATION_CODE, 11); + prepareAndShowBottomSheetWithBundle(bundle); } private void initSearchView() { @@ -541,7 +567,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ if (!isNewConversationView) { UserItem userItem = (UserItem) adapter.getItem(position); RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), "1", - userItem.getModel().getUserId()); + userItem.getModel().getUserId(), null); ncApi.createRoom(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) .subscribeOn(Schedulers.newThread()) @@ -635,4 +661,25 @@ public class ContactsController extends BaseController implements SearchView.OnQ public void onFastScrollerStateChange(boolean scrolling) { swipeRefreshLayout.setEnabled(!scrolling); } + + + private void prepareAndShowBottomSheetWithBundle(Bundle bundle) { + if (view == null) { + view = getActivity().getLayoutInflater().inflate(R.layout.bottom_sheet, null, false); + } + + getChildRouter((ViewGroup) view).setRoot( + RouterTransaction.with(new EntryMenuController(bundle)) + .popChangeHandler(new VerticalChangeHandler()) + .pushChangeHandler(new VerticalChangeHandler())); + + if (bottomSheet == null) { + bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); + } + + bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + + bottomSheet.show(); + bottomSheet.findViewById(R.id.extended_edit_text).invalidate(); + } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java index e15a24bee..a5ceb7bd6 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java @@ -82,8 +82,12 @@ public class EntryMenuController extends BaseController { private String name; private String callUrl; + private Bundle originalBundle; + public EntryMenuController(Bundle args) { super(args); + originalBundle = args; + this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE); if (args.containsKey(BundleKeys.KEY_ROOM)) { this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); @@ -130,7 +134,7 @@ public class EntryMenuController extends BaseController { getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); - } else if (operationCode != 7 && operationCode != 10) { + } else if (operationCode != 7 && operationCode != 10 && operationCode != 11) { eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); bundle = new Bundle(); if (operationCode == 4 || operationCode == 6) { @@ -153,7 +157,7 @@ public class EntryMenuController extends BaseController { getActivity().startActivity(intent); eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); } - } else { + } else if (operationCode != 11) { eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); bundle = new Bundle(); bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode); @@ -162,6 +166,13 @@ public class EntryMenuController extends BaseController { .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); + } else if (operationCode == 11) { + eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME, editText.getText().toString()); + getRouter().pushController(RouterTransaction.with(new OperationsMenuController(originalBundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } } @@ -239,6 +250,7 @@ public class EntryMenuController extends BaseController { String labelText = ""; switch (operationCode) { + case 11: case 2: labelText = getResources().getString(R.string.nc_call_name); break; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java index e022db638..5ca60ce7d 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java @@ -42,9 +42,12 @@ import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.BottomSheetLockEvent; +import com.nextcloud.talk.models.RetrofitBucket; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.call.CallOverall; import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall; +import com.nextcloud.talk.models.json.generic.GenericOverall; +import com.nextcloud.talk.models.json.participants.AddParticipantOverall; import com.nextcloud.talk.models.json.rooms.Room; import com.nextcloud.talk.models.json.rooms.RoomOverall; import com.nextcloud.talk.utils.ApiUtils; @@ -56,6 +59,8 @@ import com.nextcloud.talk.utils.database.user.UserUtils; import org.greenrobot.eventbus.EventBus; import org.parceler.Parcels; +import java.util.ArrayList; + import javax.inject.Inject; import autodagger.AutoInjector; @@ -106,6 +111,12 @@ public class OperationsMenuController extends BaseController { private Disposable disposable; + private Room.RoomType conversationType; + private ArrayList invitedUsers = new ArrayList<>(); + private String conversationName; + + private String credentials; + public OperationsMenuController(Bundle args) { super(args); this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE); @@ -115,6 +126,15 @@ public class OperationsMenuController extends BaseController { this.callPassword = args.getString(BundleKeys.KEY_CALL_PASSWORD, ""); this.callUrl = args.getString(BundleKeys.KEY_CALL_URL, ""); + + this.conversationName = args.getString(BundleKeys.KEY_CONVERSATION_NAME, ""); + if (args.containsKey(BundleKeys.KEY_INVITED_PARTICIPANTS)) { + this.invitedUsers = args.getStringArrayList(BundleKeys.KEY_INVITED_PARTICIPANTS); + } + + if (args.containsKey(BundleKeys.KEY_CONVERSATION_TYPE)) { + this.conversationType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_CONVERSATION_TYPE)); + } } @Override @@ -144,7 +164,7 @@ public class OperationsMenuController extends BaseController { } if (userEntity != null) { - String credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); + credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); if (!TextUtils.isEmpty(baseUrl) && !baseUrl.equals(userEntity.getBaseUrl())) { credentials = null; @@ -282,6 +302,84 @@ public class OperationsMenuController extends BaseController { } }); break; + case 11: + RetrofitBucket retrofitBucket; + boolean isGroupCallWorkaround = false; + if (conversationType.equals(Room.RoomType.ROOM_PUBLIC_CALL) || + !userEntity.hasSpreedCapabilityWithName("empty-group-room")) { + retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), + "3", null, conversationName); + } else { + String roomType = "2"; + if (!userEntity.hasSpreedCapabilityWithName("empty-group-room")) { + isGroupCallWorkaround = true; + roomType = "3"; + } + retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), + roomType, null, conversationName); + } + + String finalCredentials1 = credentials; + final boolean isGroupCallWorkaroundFinal = isGroupCallWorkaround; + ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .retry(1) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(RoomOverall roomOverall) { + room = roomOverall.getOcs().getData(); + if (conversationType.equals(Room.RoomType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) { + ncApi.makeRoomPrivate(finalCredentials1, ApiUtils.getUrlForRoomVisibility + (userEntity.getBaseUrl(), room.getToken())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .retry(1) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(GenericOverall genericOverall) { + inviteUsersToAConversation(); + } + + @Override + public void onError(Throwable e) { + showResultImage(false, false); + dispose(); + } + + @Override + public void onComplete() { + dispose(); + } + }); + } else { + inviteUsersToAConversation(); + } + } + + @Override + public void onError(Throwable e) { + showResultImage(false, false); + dispose(); + } + + @Override + public void onComplete() { + dispose(); + } + }); + + break; case 99: ncApi.joinRoom(credentials, ApiUtils.getUrlForRoomParticipants(baseUrl, conversationToken), callPassword) @@ -353,12 +451,59 @@ public class OperationsMenuController extends BaseController { dispose(); } + private void inviteUsersToAConversation() { + RetrofitBucket retrofitBucket; + final ArrayList localInvitedUsers = invitedUsers; + if (localInvitedUsers.size() > 0) { + for (int i = 0; i < invitedUsers.size(); i++) { + final String userId = invitedUsers.get(i); + retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(userEntity.getBaseUrl(), room.getToken(), + userId); + + ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .retry(1) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(AddParticipantOverall addParticipantOverall) { + + } + + @Override + public void onError(Throwable e) { + dispose(); + } + + @Override + public void onComplete() { + synchronized (localInvitedUsers) { + localInvitedUsers.remove(userId); + } + + if (localInvitedUsers.size() == 0) { + initiateCall(); + } + dispose(); + } + }); + } + } else { + showResultImage(true, false); + } + } + private void initiateCall() { eventBus.post(new BottomSheetLockEvent(true, 0, true, true)); Bundle bundle = new Bundle(); bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken()); bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); - if (!baseUrl.equals(userEntity.getBaseUrl())) { + if (baseUrl != null && !baseUrl.equals(userEntity.getBaseUrl())) { bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, baseUrl); } bundle.putString(BundleKeys.KEY_CALL_SESSION, callSession); diff --git a/app/src/main/java/com/nextcloud/talk/models/database/User.java b/app/src/main/java/com/nextcloud/talk/models/database/User.java index 34be44c42..4775b5d5b 100644 --- a/app/src/main/java/com/nextcloud/talk/models/database/User.java +++ b/app/src/main/java/com/nextcloud/talk/models/database/User.java @@ -59,7 +59,7 @@ public interface User extends Parcelable, Persistable, Serializable { boolean getScheduledForDeletion(); - default boolean checkForSpreedCapability(String capabilityName) { + default boolean hasSpreedCapabilityWithName(String capabilityName) { try { Capabilities capabilities = LoganSquare.parse(this.getCapabilities(), Capabilities.class); if (capabilities.getSpreedCapability() != null && capabilities.getSpreedCapability().getFeatures() != null) { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java b/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java index 647fca189..906f520f7 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java @@ -86,6 +86,7 @@ public class Room { return (canModerate() && ((participants != null && participants.size() > 2) || numberOfGuests > 0)); } + @Parcel public enum RoomType { DUMMY, ROOM_TYPE_ONE_TO_ONE_CALL, diff --git a/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java b/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java index 96df29120..f0ac350ff 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java @@ -88,7 +88,8 @@ public class AccountUtils { PackageManager packageManager = context.getPackageManager(); String appName = ""; try { - appName = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)); + appName = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, + PackageManager.GET_META_DATA)); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Failed to get app name based on package"); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index 820afd52a..17b05dafb 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -20,6 +20,7 @@ package com.nextcloud.talk.utils; import android.net.Uri; +import android.support.annotation.Nullable; import com.nextcloud.talk.BuildConfig; import com.nextcloud.talk.R; @@ -73,13 +74,21 @@ public class ApiUtils { return baseUrl + ocsApiVersion + spreedApiVersion + "/room/" + token; } - public static RetrofitBucket getRetrofitBucketForCreateRoom(String baseUrl, String roomType, String invite) { + public static RetrofitBucket getRetrofitBucketForCreateRoom(String baseUrl, String roomType, + @Nullable String invite, + @Nullable String conversationName) { RetrofitBucket retrofitBucket = new RetrofitBucket(); retrofitBucket.setUrl(baseUrl + ocsApiVersion + spreedApiVersion + "/room"); Map queryMap = new HashMap<>(); queryMap.put("roomType", roomType); - queryMap.put("invite", invite); + if (invite != null) { + queryMap.put("invite", invite); + } + + if (conversationName != null) { + queryMap.put("roomName", conversationName); + } retrofitBucket.setQueryMap(queryMap); diff --git a/app/src/main/java/com/nextcloud/talk/utils/DeviceUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DeviceUtils.java index d58c3acd9..a4c6dce13 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DeviceUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DeviceUtils.java @@ -40,8 +40,8 @@ public class DeviceUtils { try { @SuppressLint("PrivateApi") Class appOpsUtilsClass = Class.forName("android.miui.AppOpsUtils"); if (appOpsUtilsClass != null) { - Method setApplicationAutoStartMethod = appOpsUtilsClass.getDeclaredMethod("setApplicationAutoStart", Context.class, String - .class, Boolean.TYPE); + Method setApplicationAutoStartMethod = appOpsUtilsClass.getMethod("setApplicationAutoStart", Context + .class, String.class, Boolean.TYPE); if (setApplicationAutoStartMethod != null) { Context applicationContext = NextcloudTalkApplication.getSharedApplication().getApplicationContext(); setApplicationAutoStartMethod.invoke(appOpsUtilsClass, applicationContext, applicationContext diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java index a1efbaa8f..01afe5bb2 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java @@ -26,14 +26,14 @@ public class BundleKeys { public static final String KEY_BASE_URL = "KEY_BASE_URL"; public static final String KEY_IS_ACCOUNT_IMPORT = "KEY_IS_ACCOUNT_IMPORT"; public static final String KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL"; - public static final String KEY_ROOM = "KEY_ROOM"; + public static final String KEY_ROOM = "KEY_CONVERSATION"; public static final String KEY_OPERATION_CODE = "KEY_OPERATION_CODE"; public static final String KEY_MENU_TYPE = "KEY_MENU_TYPE"; 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"; + public static final String KEY_CALL_PASSWORD = "KEY_CONVERSATION_PASSWORD"; + public static final String KEY_CALL_SESSION = "KEY_CONVERSATION_SESSION"; public static final String KEY_ROOM_TOKEN = "KEY_ROOM_TOKEN"; public static final String KEY_USER_ENTITY = "KEY_USER_ENTITY"; public static final String KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION"; @@ -43,4 +43,7 @@ public class BundleKeys { public static final String KEY_NOTIFICATION_SUBJECT = "KEY_NOTIFICATION_SUBJECT"; public static final String KEY_NOTIFICATION_SIGNATURE = "KEY_NOTIFICATION_SIGNATURE"; public static final String KEY_INTERNAL_USER_ID = "KEY_INTERNAL_USER_ID"; + public static final String KEY_CONVERSATION_TYPE = "KEY_CONVERSATION_TYPE"; + public static final String KEY_INVITED_PARTICIPANTS = "KEY_INVITED_PARTICIPANTS"; + public static final String KEY_CONVERSATION_NAME = "KEY_CONVERSATION_NAME"; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec4b90768..25c248b09 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -122,7 +122,7 @@ You may attempt to join the call via web browser. OK, all done! OK - Call name + Conversation name Proceed The name you entered is the same as the existing one Conversation link is not valid