diff options
author | Tim Krüger <t@timkrueger.me> | 2022-09-26 14:20:43 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-26 14:20:43 +0300 |
commit | 9e9ee868bad206fbe43789cd299722ec2afb9285 (patch) | |
tree | bf9c02b98ba9860b4e1594fb0eab6c41a905c329 | |
parent | 0fbe9eb3b0051ca3effcd513db555de45b320409 (diff) | |
parent | c84c6445a6a9039caded58dfca307da8a8d27261 (diff) |
Merge pull request #2427 from nextcloud/backport/2367/stable-15.0v15.0.0rc2
[stable-15.0] Respect participant permissions
18 files changed, 407 insertions, 292 deletions
diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index f0a1ddeb2..9085f6abe 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2,6 +2,8 @@ * Nextcloud Talk application * * @author Mario Danic + * @author Tim Krüger + * Copyright (C) 2022 Tim Krüger <t@timkrueger.me> * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> * * This program is free software: you can redistribute it and/or modify @@ -90,7 +92,6 @@ import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.NotificationUtils; import com.nextcloud.talk.utils.animations.PulseAnimation; -import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil; import com.nextcloud.talk.utils.power.PowerManagerUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; @@ -163,6 +164,17 @@ import okhttp3.Cache; import pub.devrel.easypermissions.AfterPermissionGranted; import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_WITHOUT_NOTIFICATION; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_PASSWORD; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MODIFIED_BASE_URL; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN; +import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY; import static com.nextcloud.talk.webrtc.Globals.JOB_ID; import static com.nextcloud.talk.webrtc.Globals.PARTICIPANTS_UPDATE; import static com.nextcloud.talk.webrtc.Globals.ROOM_TOKEN; @@ -246,7 +258,7 @@ public class CallActivity extends CallBaseActivity { private Handler cameraSwitchHandler = new Handler(); // push to talk - private boolean isPTTActive = false; + private boolean isPushToTalkActive = false; private PulseAnimation pulseAnimation; private String baseUrl; @@ -283,6 +295,9 @@ public class CallActivity extends CallBaseActivity { } }); + private boolean canPublishAudioStream; + private boolean canPublishVideoStream; + @SuppressLint("ClickableViewAccessibility") @Override public void onCreate(Bundle savedInstanceState) { @@ -297,21 +312,23 @@ public class CallActivity extends CallBaseActivity { hideNavigationIfNoPipAvailable(); Bundle extras = getIntent().getExtras(); - roomId = extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), ""); - roomToken = extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), ""); - conversationUser = extras.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY()); - conversationPassword = extras.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), ""); - conversationName = extras.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), ""); - isVoiceOnlyCall = extras.getBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false); - isCallWithoutNotification = extras.getBoolean(BundleKeys.INSTANCE.getKEY_CALL_WITHOUT_NOTIFICATION(), false); + roomId = extras.getString(KEY_ROOM_ID, ""); + roomToken = extras.getString(KEY_ROOM_TOKEN, ""); + conversationUser = extras.getParcelable(KEY_USER_ENTITY); + conversationPassword = extras.getString(KEY_CONVERSATION_PASSWORD, ""); + conversationName = extras.getString(KEY_CONVERSATION_NAME, ""); + isVoiceOnlyCall = extras.getBoolean(KEY_CALL_VOICE_ONLY, false); + isCallWithoutNotification = extras.getBoolean(KEY_CALL_WITHOUT_NOTIFICATION, false); + canPublishAudioStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO); + canPublishVideoStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO); - if (extras.containsKey(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL())) { - isIncomingCallFromNotification = extras.getBoolean(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL()); + if (extras.containsKey(KEY_FROM_NOTIFICATION_START_CALL)) { + isIncomingCallFromNotification = extras.getBoolean(KEY_FROM_NOTIFICATION_START_CALL); } credentials = ApiUtils.getCredentials(conversationUser.getUsername(), conversationUser.getToken()); - baseUrl = extras.getString(BundleKeys.INSTANCE.getKEY_MODIFIED_BASE_URL(), ""); + baseUrl = extras.getString(KEY_MODIFIED_BASE_URL, ""); if (TextUtils.isEmpty(baseUrl)) { baseUrl = conversationUser.getBaseUrl(); } @@ -377,23 +394,41 @@ public class CallActivity extends CallBaseActivity { audioOutputDialog.show(); }); - binding.microphoneButton.setOnClickListener(l -> onMicrophoneClick()); - binding.microphoneButton.setOnLongClickListener(l -> { - if (!microphoneOn) { - callControlHandler.removeCallbacksAndMessages(null); - callInfosHandler.removeCallbacksAndMessages(null); - cameraSwitchHandler.removeCallbacksAndMessages(null); - isPTTActive = true; - binding.callControls.setVisibility(View.VISIBLE); - if (!isVoiceOnlyCall) { - binding.switchSelfVideoButton.setVisibility(View.VISIBLE); + if (canPublishAudioStream) { + binding.microphoneButton.setOnClickListener(l -> onMicrophoneClick()); + binding.microphoneButton.setOnLongClickListener(l -> { + if (!microphoneOn) { + callControlHandler.removeCallbacksAndMessages(null); + callInfosHandler.removeCallbacksAndMessages(null); + cameraSwitchHandler.removeCallbacksAndMessages(null); + isPushToTalkActive = true; + binding.callControls.setVisibility(View.VISIBLE); + if (!isVoiceOnlyCall) { + binding.switchSelfVideoButton.setVisibility(View.VISIBLE); + } } - } - onMicrophoneClick(); - return true; - }); + onMicrophoneClick(); + return true; + }); + } else { + binding.microphoneButton.setOnClickListener( + l -> Toast.makeText(context, + R.string.nc_not_allowed_to_activate_audio, + Toast.LENGTH_SHORT + ).show() + ); + } - binding.cameraButton.setOnClickListener(l -> onCameraClick()); + if (canPublishVideoStream) { + binding.cameraButton.setOnClickListener(l -> onCameraClick()); + } else { + binding.cameraButton.setOnClickListener( + l -> Toast.makeText(context, + R.string.nc_not_allowed_to_activate_video, + Toast.LENGTH_SHORT + ).show() + ); + } binding.hangupButton.setOnClickListener(l -> { hangup(true); @@ -548,7 +583,7 @@ public class CallActivity extends CallBaseActivity { } } - checkPermissions(); + checkDevicePermissions(); } @Override @@ -695,7 +730,7 @@ public class CallActivity extends CallBaseActivity { } - private void checkPermissions() { + private void checkDevicePermissions() { if (isVoiceOnlyCall) { onMicrophoneClick(); } else { @@ -754,7 +789,7 @@ public class CallActivity extends CallBaseActivity { binding.switchSelfVideoButton.setVisibility(View.VISIBLE); } - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && canPublishVideoStream) { if (!videoOn) { onCameraClick(); } @@ -765,7 +800,7 @@ public class CallActivity extends CallBaseActivity { } } - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE) && canPublishAudioStream) { if (!microphoneOn) { onMicrophoneClick(); } @@ -878,6 +913,22 @@ public class CallActivity extends CallBaseActivity { } public void onMicrophoneClick() { + + if (!canPublishAudioStream) { + microphoneOn = false; + binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px); + toggleMedia(false, false); + } + + if (isVoiceOnlyCall && !isConnectionEstablished()) { + fetchSignalingSettings(); + } + + if (!canPublishAudioStream) { + // In the case no audio stream will be published it's not needed to check microphone permissions + return; + } + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { if (!appPreferences.getPushToTalkIntroShown()) { @@ -905,7 +956,7 @@ public class CallActivity extends CallBaseActivity { appPreferences.setPushToTalkIntroShown(true); } - if (!isPTTActive) { + if (!isPushToTalkActive) { microphoneOn = !microphoneOn; if (microphoneOn) { @@ -926,11 +977,6 @@ public class CallActivity extends CallBaseActivity { pulseAnimation.start(); toggleMedia(true, false); } - - if (isVoiceOnlyCall && !isConnectionEstablished()) { - fetchSignalingSettings(); - } - } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) { // Microphone permission is permanently denied so we cannot request it normally. @@ -947,6 +993,14 @@ public class CallActivity extends CallBaseActivity { } public void onCameraClick() { + + if (!canPublishVideoStream) { + videoOn = false; + binding.cameraButton.getHierarchy().setPlaceholderImage(R.drawable.ic_videocam_off_white_24px); + binding.switchSelfVideoButton.setVisibility(View.GONE); + return; + } + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { videoOn = !videoOn; @@ -1057,7 +1111,7 @@ public class CallActivity extends CallBaseActivity { if (spotlightView != null && spotlightView.getVisibility() != View.GONE) { spotlightView.setVisibility(View.GONE); } - } else if (!isPTTActive) { + } else if (!isPushToTalkActive) { float alpha; long duration; @@ -1106,7 +1160,7 @@ public class CallActivity extends CallBaseActivity { callControlHandler.postDelayed(new Runnable() { @Override public void run() { - if (!isPTTActive) { + if (!isPushToTalkActive) { animateCallControls(false, 0); } } @@ -1133,7 +1187,7 @@ public class CallActivity extends CallBaseActivity { callInfosHandler.postDelayed(new Runnable() { @Override public void run() { - if (!isPTTActive) { + if (!isPushToTalkActive) { animateCallControls(false, 0); } } @@ -1374,12 +1428,14 @@ public class CallActivity extends CallBaseActivity { } private void performCall() { - int inCallFlag; - if (isVoiceOnlyCall) { - inCallFlag = Participant.InCallFlags.IN_CALL + Participant.InCallFlags.WITH_AUDIO; - } else { - inCallFlag = - Participant.InCallFlags.IN_CALL + Participant.InCallFlags.WITH_AUDIO + Participant.InCallFlags.WITH_VIDEO; + int inCallFlag = Participant.InCallFlags.IN_CALL; + + if (canPublishAudioStream) { + inCallFlag += Participant.InCallFlags.WITH_AUDIO; + } + + if (!isVoiceOnlyCall && canPublishVideoStream) { + inCallFlag += Participant.InCallFlags.WITH_VIDEO; } int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1}); @@ -1485,7 +1541,7 @@ public class CallActivity extends CallBaseActivity { private void initiateCall() { if (!TextUtils.isEmpty(roomToken)) { - checkPermissions(); + checkDevicePermissions(); } else { handleFromNotification(); } @@ -2292,7 +2348,7 @@ public class CallActivity extends CallBaseActivity { if (peerConnectionWrapper != null) { PeerConnection.IceConnectionState iceConnectionState = peerConnectionWrapper.getPeerConnection().iceConnectionState(); connected = iceConnectionState == PeerConnection.IceConnectionState.CONNECTED || - iceConnectionState == PeerConnection.IceConnectionState.COMPLETED; + iceConnectionState == PeerConnection.IceConnectionState.COMPLETED; } String nick; @@ -2471,7 +2527,7 @@ public class CallActivity extends CallBaseActivity { binding.callInfosLinearLayout.setVisibility(View.GONE); } - if (!isPTTActive) { + if (!isPushToTalkActive) { animateCallControls(false, 5000); } @@ -2590,8 +2646,8 @@ public class CallActivity extends CallBaseActivity { @Override public boolean onTouch(View v, MotionEvent event) { v.onTouchEvent(event); - if (event.getAction() == MotionEvent.ACTION_UP && isPTTActive) { - isPTTActive = false; + if (event.getAction() == MotionEvent.ACTION_UP && isPushToTalkActive) { + isPushToTalkActive = false; binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px); pulseAnimation.stop(); toggleMedia(false, false); diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java index acaa16e64..f0d3c6303 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java @@ -129,9 +129,9 @@ public class CallNotificationActivity extends CallBaseActivity { eventBus.post(new CallNotificationClick()); Bundle extras = getIntent().getExtras(); - this.roomId = extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), ""); - this.currentConversation = Parcels.unwrap(extras.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM())); - this.userBeingCalled = extras.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY()); + this.roomId = extras.getString(BundleKeys.KEY_ROOM_ID, ""); + this.currentConversation = Parcels.unwrap(extras.getParcelable(BundleKeys.KEY_ROOM)); + this.userBeingCalled = extras.getParcelable(BundleKeys.KEY_USER_ENTITY); this.originalBundle = extras; credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken()); @@ -169,13 +169,13 @@ public class CallNotificationActivity extends CallBaseActivity { private void initClickListeners() { binding.callAnswerVoiceOnlyView.setOnClickListener(l -> { Log.d(TAG, "accept call (voice only)"); - originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), true); + originalBundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true); proceedToCall(); }); binding.callAnswerCameraView.setOnClickListener(l -> { Log.d(TAG, "accept call (with video)"); - originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false); + originalBundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false); proceedToCall(); }); @@ -202,8 +202,8 @@ public class CallNotificationActivity extends CallBaseActivity { } private void proceedToCall() { - originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken()); - originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName()); + originalBundle.putString(BundleKeys.KEY_ROOM_TOKEN, currentConversation.getToken()); + originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME, currentConversation.getDisplayName()); Intent intent = new Intent(this, CallActivity.class); intent.putExtras(originalBundle); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 8a1502543..7d1ad5870 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -156,7 +156,6 @@ import com.nextcloud.talk.ui.dialog.ShowReactionsDialog import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback import com.nextcloud.talk.utils.ApiUtils -import com.nextcloud.talk.utils.AttendeePermissionsUtil import com.nextcloud.talk.utils.ConductorRemapping import com.nextcloud.talk.utils.ConductorRemapping.remapChatController import com.nextcloud.talk.utils.ContactUtils @@ -166,6 +165,7 @@ import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.ImageEmojiEditText import com.nextcloud.talk.utils.MagicCharPolicy import com.nextcloud.talk.utils.NotificationUtils +import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME @@ -284,7 +284,7 @@ class ChatController(args: Bundle) : lateinit var mediaPlayerHandler: Handler private var currentlyPlayedVoiceMessage: ChatMessage? = null - var hasChatPermission: Boolean = false + private lateinit var participantPermissions: ParticipantPermissions private var videoURI: Uri? = null @@ -306,6 +306,7 @@ class ChatController(args: Bundle) : if (args.containsKey(KEY_ACTIVE_CONVERSATION)) { this.currentConversation = Parcels.unwrap<Conversation>(args.getParcelable(KEY_ACTIVE_CONVERSATION)) + this.participantPermissions = ParticipantPermissions(conversationUser!!, currentConversation!!) } this.roomPassword = args.getString(BundleKeys.KEY_CONVERSATION_PASSWORD, "") @@ -353,11 +354,7 @@ class ChatController(args: Bundle) : ) loadAvatarForStatusBar() setTitle() - - hasChatPermission = - AttendeePermissionsUtil(currentConversation!!.permissions).hasChatPermission( - conversationUser - ) + participantPermissions = ParticipantPermissions(conversationUser, currentConversation!!) try { setupSwipeToReply() @@ -395,7 +392,10 @@ class ChatController(args: Bundle) : } private fun setupSwipeToReply() { - if (hasChatPermission && !isReadOnlyConversation()) { + if (this::participantPermissions.isInitialized && + participantPermissions.hasChatPermission() && + !isReadOnlyConversation() + ) { val messageSwipeController = MessageSwipeCallback( activity!!, object : MessageSwipeActions { @@ -434,6 +434,7 @@ class ChatController(args: Bundle) : if (roomId == conversation.roomId) { roomToken = conversation.token currentConversation = conversation + participantPermissions = ParticipantPermissions(conversationUser!!, currentConversation!!) setTitle() getRoomInfo() break @@ -1261,7 +1262,7 @@ class ChatController(args: Bundle) : if (isAlive()) { if (isReadOnlyConversation() || shouldShowLobby() || - !hasChatPermission + !participantPermissions.hasChatPermission() ) { binding.messageInputView.visibility = View.GONE } else { @@ -1272,7 +1273,9 @@ class ChatController(args: Bundle) : private fun shouldShowLobby(): Boolean { if (currentConversation != null) { - return currentConversation?.shouldShowLobby(conversationUser!!) == true + return currentConversation?.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY && + currentConversation?.canModerate(conversationUser!!) == false && + !participantPermissions.canIgnoreLobby() } return false } @@ -1311,14 +1314,14 @@ class ChatController(args: Bundle) : private fun checkLobbyState() { if (currentConversation != null && - currentConversation?.isLobbyViewApplicable(conversationUser!!) ?: false && + currentConversation?.isLobbyViewApplicable(conversationUser!!) == true && isAlive() ) { if (!checkingLobbyStatus) { getRoomInfo() } - if (currentConversation?.shouldShowLobby(conversationUser!!) ?: false) { + if (shouldShowLobby()) { binding.lobby.lobbyView.visibility = View.VISIBLE binding.messagesListView.visibility = View.GONE binding.messageInputView.visibility = View.GONE @@ -1610,8 +1613,8 @@ class ChatController(args: Bundle) : private fun uploadFile(fileUri: String, isVoiceMessage: Boolean) { var metaData = "" - if (!hasChatPermission) { - Log.w(TAG, "uploading file is forbidden because of missing attendee permissions") + if (!participantPermissions.hasChatPermission()) { + Log.w(TAG, "uploading file(s) is forbidden because of missing attendee permissions") return } @@ -2146,10 +2149,6 @@ class ChatController(args: Bundle) : } pullChatMessagesPending = true - if (currentConversation != null && currentConversation!!.shouldShowLobby(conversationUser!!)) { - // return - } - val fieldMap = HashMap<String, Int>() fieldMap["includeLastKnown"] = 0 @@ -2727,7 +2726,8 @@ class ChatController(args: Bundle) : } private fun startACall(isVoiceOnlyCall: Boolean, callWithoutNotification: Boolean) { - if (currentConversation?.canStartCall == false && currentConversation?.hasCall == false) { + val pp = ParticipantPermissions(conversationUser!!, currentConversation!!) + if (!pp.canStartCall() && currentConversation?.hasCall == false) { Toast.makeText(context, R.string.startCallForbidden, Toast.LENGTH_LONG).show() } else { ApplicationWideCurrentRoomHolder.getInstance().isDialing = true @@ -2747,6 +2747,14 @@ class ChatController(args: Bundle) : bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, roomPassword) bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, conversationUser?.baseUrl) bundle.putString(KEY_CONVERSATION_NAME, it.displayName) + bundle.putBoolean( + BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO, + participantPermissions.canPublishAudio() + ) + bundle.putBoolean( + BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO, + participantPermissions.canPublishVideo() + ) if (isVoiceOnlyCall) { bundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true) @@ -2774,7 +2782,7 @@ class ChatController(args: Bundle) : currentConversation, chatMessage, conversationUser, - hasChatPermission, + participantPermissions.hasChatPermission(), ncApi ).show() } @@ -2802,7 +2810,7 @@ class ChatController(args: Bundle) : conversationUser, currentConversation, isShowMessageDeletionButton(message), - hasChatPermission, + participantPermissions.hasChatPermission(), ncApi ).show() } @@ -2814,7 +2822,7 @@ class ChatController(args: Bundle) : } fun deleteMessage(message: IMessage?) { - if (!hasChatPermission) { + if (!participantPermissions.hasChatPermission()) { Log.w( TAG, "Deletion of message is skipped because of restrictions by permissions. " + @@ -3144,7 +3152,7 @@ class ChatController(args: Bundle) : message.hasFileAttachment() -> false OBJECT_MESSAGE == message.message -> false !CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "delete-messages") -> false - !hasChatPermission -> false + !participantPermissions.hasChatPermission() -> false else -> true } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.kt index ed42b9ac4..14abbc2f2 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.kt @@ -104,7 +104,7 @@ import com.nextcloud.talk.ui.dialog.ChooseAccountShareToDialogFragment import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils -import com.nextcloud.talk.utils.AttendeePermissionsUtil +import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ConductorRemapping.remapChatController import com.nextcloud.talk.utils.DisplayUtils @@ -938,13 +938,11 @@ class ConversationsListController(bundle: Bundle) : private fun handleConversation(conversation: Conversation?) { selectedConversation = conversation if (selectedConversation != null && activity != null) { - val hasChatPermission = AttendeePermissionsUtil(selectedConversation!!.permissions).hasChatPermission( - currentUser!! - ) + val hasChatPermission = ParticipantPermissions(currentUser!!, selectedConversation!!).hasChatPermission() if (showShareToScreen) { if (hasChatPermission && !isReadOnlyConversation(selectedConversation!!) && - !selectedConversation!!.shouldShowLobby(currentUser!!) + !shouldShowLobby(selectedConversation!!) ) { handleSharedData() } else { @@ -963,6 +961,13 @@ class ConversationsListController(bundle: Bundle) : } } + private fun shouldShowLobby(conversation: Conversation): Boolean { + val participantPermissions = ParticipantPermissions(currentUser!!, conversation) + return conversation.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY && + !conversation.canModerate(currentUser!!) && + !participantPermissions.canIgnoreLobby() + } + private fun isReadOnlyConversation(conversation: Conversation): Boolean { return conversation.conversationReadOnlyState === Conversation.ConversationReadOnlyState.CONVERSATION_READ_ONLY diff --git a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java index 6fe0a7330..4417b096c 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java @@ -63,18 +63,18 @@ public class AddParticipantsToConversation extends Worker { @Override public Result doWork() { Data data = getInputData(); - String[] selectedUserIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_USERS()); - String[] selectedGroupIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_GROUPS()); - String[] selectedCircleIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_CIRCLES()); - String[] selectedEmails = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_EMAILS()); + String[] selectedUserIds = data.getStringArray(BundleKeys.KEY_SELECTED_USERS); + String[] selectedGroupIds = data.getStringArray(BundleKeys.KEY_SELECTED_GROUPS); + String[] selectedCircleIds = data.getStringArray(BundleKeys.KEY_SELECTED_CIRCLES); + String[] selectedEmails = data.getStringArray(BundleKeys.KEY_SELECTED_EMAILS); User user = userManager.getUserWithInternalId( - data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1)) + data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1)) .blockingGet(); int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {ApiUtils.APIv4, 1}); - String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_TOKEN()); + String conversationToken = data.getString(BundleKeys.KEY_TOKEN); String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken()); RetrofitBucket retrofitBucket; diff --git a/app/src/main/java/com/nextcloud/talk/jobs/CapabilitiesWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/CapabilitiesWorker.java index 3c8b20115..ba20aab32 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/CapabilitiesWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/CapabilitiesWorker.java @@ -109,7 +109,7 @@ public class CapabilitiesWorker extends Worker { Data data = getInputData(); - long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1); + long internalUserId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1); List<User> userEntityObjectList = new ArrayList<>(); boolean userExists = userManager.getUserWithInternalId(internalUserId).isEmpty().blockingGet(); diff --git a/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java index 0f888b3d0..16e5851b6 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java @@ -75,8 +75,8 @@ public class DeleteConversationWorker extends Worker { @Override public Result doWork() { Data data = getInputData(); - long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1); - String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()); + long operationUserId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1); + String conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN); User operationUser = userManager.getUserWithId(operationUserId).blockingGet(); if (operationUser != null) { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java index fcf633c02..87b15e690 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java @@ -79,8 +79,8 @@ public class LeaveConversationWorker extends Worker { @Override public Result doWork() { Data data = getInputData(); - long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1); - String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()); + long operationUserId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1); + String conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN); User operationUser = userManager.getUserWithId(operationUserId).blockingGet(); if (operationUser != null) { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java index 3f7288fae..efcb75dc7 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java @@ -138,7 +138,7 @@ public class NotificationWorker extends Worker { importantConversation = arbitraryStorageManager.getStorageSetting( UserIdUtils.INSTANCE.getIdForUser(user), "important_conversation", - intent.getExtras().getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN())) + intent.getExtras().getString(BundleKeys.KEY_ROOM_TOKEN)) .map(arbitraryStorage -> { if (arbitraryStorage != null && arbitraryStorage.getValue() != null) { return Boolean.parseBoolean(arbitraryStorage.getValue()); @@ -154,7 +154,7 @@ public class NotificationWorker extends Worker { int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {ApiUtils.APIv4, 1}); ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, user.getBaseUrl(), - intent.getExtras().getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) + intent.getExtras().getString(BundleKeys.KEY_ROOM_TOKEN))) .blockingSubscribe(new Observer<RoomOverall>() { @Override public void onSubscribe(Disposable d) { @@ -165,7 +165,7 @@ public class NotificationWorker extends Worker { public void onNext(RoomOverall roomOverall) { Conversation conversation = roomOverall.getOcs().getData(); - intent.putExtra(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); + intent.putExtra(BundleKeys.KEY_ROOM, Parcels.wrap(conversation)); if (conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) || (!TextUtils.isEmpty(conversation.getObjectType()) && "share:password".equals (conversation.getObjectType()))) { @@ -351,12 +351,12 @@ public class NotificationWorker extends Worker { } Bundle notificationInfo = new Bundle(); - notificationInfo.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), + notificationInfo.putLong(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.getUser().getId()); // could be an ID or a TOKEN - notificationInfo.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), + notificationInfo.putString(BundleKeys.KEY_ROOM_TOKEN, decryptedPushMessage.getId()); - notificationInfo.putLong(BundleKeys.INSTANCE.getKEY_NOTIFICATION_ID(), + notificationInfo.putLong(BundleKeys.KEY_NOTIFICATION_ID, decryptedPushMessage.getNotificationId()); notificationBuilder.setExtras(notificationInfo); @@ -442,10 +442,10 @@ public class NotificationWorker extends Worker { // NOTE - systemNotificationId is an internal ID used on the device only. // It is NOT the same as the notification ID used in communication with the server. - actualIntent.putExtra(BundleKeys.INSTANCE.getKEY_SYSTEM_NOTIFICATION_ID(), systemNotificationId); - actualIntent.putExtra(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), + actualIntent.putExtra(BundleKeys.KEY_SYSTEM_NOTIFICATION_ID, systemNotificationId); + actualIntent.putExtra(BundleKeys.KEY_INTERNAL_USER_ID, Objects.requireNonNull(signatureVerification.getUser()).getId()); - actualIntent.putExtra(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), decryptedPushMessage.getId()); + actualIntent.putExtra(BundleKeys.KEY_ROOM_TOKEN, decryptedPushMessage.getId()); actualIntent.putExtra(BundleKeys.KEY_MESSAGE_ID, messageId); int intentFlag; @@ -583,8 +583,8 @@ public class NotificationWorker extends Worker { context = getApplicationContext(); Data data = getInputData(); - String subject = data.getString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SUBJECT()); - String signature = data.getString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SIGNATURE()); + String subject = data.getString(BundleKeys.KEY_NOTIFICATION_SUBJECT); + String signature = data.getString(BundleKeys.KEY_NOTIFICATION_SIGNATURE); try { byte[] base64DecodedSubject = Base64.decode(subject, Base64.DEFAULT); @@ -643,13 +643,13 @@ public class NotificationWorker extends Worker { intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), decryptedPushMessage.getId()); + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, decryptedPushMessage.getId()); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, signatureVerification.getUser()); - bundle.putBoolean(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL(), - startACall); + bundle.putBoolean(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, + startACall); intent.putExtras(bundle); @@ -657,12 +657,12 @@ public class NotificationWorker extends Worker { switch (decryptedPushMessage.getType()) { case "call": - if (bundle.containsKey(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN())) { + if (bundle.containsKey(BundleKeys.KEY_ROOM_TOKEN)) { showNotificationForCallWithNoPing(intent); } break; case "room": - if (bundle.containsKey(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN())) { + if (bundle.containsKey(BundleKeys.KEY_ROOM_TOKEN)) { showNotificationWithObjectData(intent); } break; diff --git a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java index 77017637e..cdaf5a92f 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java @@ -74,7 +74,7 @@ public class SignalingSettingsWorker extends Worker { Data data = getInputData(); - long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1); + long internalUserId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1); List<User> userEntityObjectList = new ArrayList<>(); boolean userExists = userManager.getUserWithInternalId(internalUserId).isEmpty().blockingGet(); diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 54e1559c7..0160f649c 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -155,10 +155,6 @@ data class Conversation( return isParticipantOwnerOrModerator && !isLockedOneToOne(conversationUser) } - fun shouldShowLobby(conversationUser: User): Boolean { - return LobbyState.LOBBY_STATE_MODERATORS_ONLY == lobbyState && !canModerate(conversationUser) - } - fun isLobbyViewApplicable(conversationUser: User): Boolean { return !canModerate(conversationUser) && (type == ConversationType.ROOM_GROUP_CALL || type == ConversationType.ROOM_PUBLIC_CALL) diff --git a/app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt deleted file mode 100644 index f7c6109da..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Marcel Hibbe - * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package com.nextcloud.talk.utils - -import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew - -/** - * see https://nextcloud-talk.readthedocs.io/en/latest/constants/#attendee-permissions - */ -class AttendeePermissionsUtil(flag: Int) { - var isDefault: Boolean = false - var isCustom: Boolean = false - var canStartCall: Boolean = false - var canJoinCall: Boolean = false - var canIgnoreLobby: Boolean = false - var canPublishAudio: Boolean = false - var canPublishVideo: Boolean = false - var canPublishScreen: Boolean = false - private var hasChatPermission: Boolean = false - - init { - isDefault = (flag and DEFAULT) == DEFAULT - isCustom = (flag and CUSTOM) == CUSTOM - canStartCall = (flag and START_CALL) == START_CALL - canJoinCall = (flag and JOIN_CALL) == JOIN_CALL - canIgnoreLobby = (flag and CAN_IGNORE_LOBBY) == CAN_IGNORE_LOBBY - canPublishAudio = (flag and PUBLISH_AUDIO) == PUBLISH_AUDIO - canPublishVideo = (flag and PUBLISH_VIDEO) == PUBLISH_VIDEO - canPublishScreen = (flag and PUBLISH_SCREEN) == PUBLISH_SCREEN - hasChatPermission = (flag and CHAT) == CHAT - } - - fun hasChatPermission(user: User): Boolean { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "chat-permission")) { - return hasChatPermission - } - // if capability is not available then the spreed version doesn't support to restrict this - return true - } - - companion object { - val TAG = AttendeePermissionsUtil::class.simpleName - const val DEFAULT = 0 - const val CUSTOM = 1 - const val START_CALL = 2 - const val JOIN_CALL = 4 - const val CAN_IGNORE_LOBBY = 8 - const val PUBLISH_AUDIO = 16 - const val PUBLISH_VIDEO = 32 - const val PUBLISH_SCREEN = 64 - const val CHAT = 128 - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt new file mode 100644 index 000000000..cadb8d894 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt @@ -0,0 +1,107 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * @author Tim Krüger + * Copyright (C) 2022 Tim Krüger <t@timkrueger.me> + * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package com.nextcloud.talk.utils + +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew + +/** + * see https://nextcloud-talk.readthedocs.io/en/latest/constants/#attendee-permissions + */ +class ParticipantPermissions( + private val user: User, + private val conversation: Conversation +) { + + val isDefault = (conversation.permissions and DEFAULT) == DEFAULT + val isCustom = (conversation.permissions and CUSTOM) == CUSTOM + private val canStartCall = (conversation.permissions and START_CALL) == START_CALL + val canJoinCall = (conversation.permissions and JOIN_CALL) == JOIN_CALL + private val canIgnoreLobby = (conversation.permissions and CAN_IGNORE_LOBBY) == CAN_IGNORE_LOBBY + private val canPublishAudio = (conversation.permissions and PUBLISH_AUDIO) == PUBLISH_AUDIO + private val canPublishVideo = (conversation.permissions and PUBLISH_VIDEO) == PUBLISH_VIDEO + val canPublishScreen = (conversation.permissions and PUBLISH_SCREEN) == PUBLISH_SCREEN + private val hasChatPermission = (conversation.permissions and CHAT) == CHAT + + private fun hasConversationPermissions(): Boolean { + return CapabilitiesUtilNew.hasSpreedFeatureCapability( + user, + "conversation-permissions" + ) + } + + fun canIgnoreLobby(): Boolean { + if (hasConversationPermissions()) { + return canIgnoreLobby + } + + return false + } + + fun canStartCall(): Boolean { + return if (hasConversationPermissions()) { + canStartCall + } else { + conversation.canStartCall + } + } + + fun canPublishAudio(): Boolean { + return if (hasConversationPermissions()) { + canPublishAudio + } else { + true + } + } + + fun canPublishVideo(): Boolean { + return if (hasConversationPermissions()) { + canPublishVideo + } else { + true + } + } + + fun hasChatPermission(): Boolean { + if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "chat-permission")) { + return hasChatPermission + } + // if capability is not available then the spreed version doesn't support to restrict this + return true + } + + companion object { + + val TAG = ParticipantPermissions::class.simpleName + const val DEFAULT = 0 + const val CUSTOM = 1 + const val START_CALL = 2 + const val JOIN_CALL = 4 + const val CAN_IGNORE_LOBBY = 8 + const val PUBLISH_AUDIO = 16 + const val PUBLISH_VIDEO = 32 + const val PUBLISH_SCREEN = 64 + const val CHAT = 128 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index 75ca6b9d3..82db195ed 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -2,6 +2,8 @@ * Nextcloud Talk application * * @author Mario Danic + * @author Tim Krüger + * Copyright (C) 2022 Tim Krüger <t@timkrueger.me> * Copyright (C) 2017 Mario Danic * * This program is free software: you can redistribute it and/or modify @@ -21,58 +23,58 @@ package com.nextcloud.talk.utils.bundle object BundleKeys { - val KEY_SELECTED_USERS = "KEY_SELECTED_USERS" - val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS" - val KEY_SELECTED_CIRCLES = "KEY_SELECTED_CIRCLES" - val KEY_SELECTED_EMAILS = "KEY_SELECTED_EMAILS" - val KEY_USERNAME = "KEY_USERNAME" - val KEY_TOKEN = "KEY_TOKEN" - val KEY_BASE_URL = "KEY_BASE_URL" - val KEY_IS_ACCOUNT_IMPORT = "KEY_IS_ACCOUNT_IMPORT" - val KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL" - val KEY_ROOM = "KEY_CONVERSATION" - val KEY_OPERATION_CODE = "KEY_OPERATION_CODE" - val KEY_MENU_TYPE = "KEY_MENU_TYPE" - val KEY_SHARE_INTENT = "KEY_SHARE_INTENT" - val KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME" - val KEY_APP_ITEM_NAME = "KEY_APP_ITEM_NAME" - val KEY_CONVERSATION_PASSWORD = "KEY_CONVERSATION_PASSWORD" - val KEY_ROOM_TOKEN = "KEY_ROOM_TOKEN" - val KEY_ROOM_ONE_TO_ONE = "KEY_ROOM_ONE_TO_ONE" - val KEY_USER_ENTITY = "KEY_USER_ENTITY" - val KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION" - val KEY_ADD_PARTICIPANTS = "KEY_ADD_PARTICIPANTS" - val KEY_EXISTING_PARTICIPANTS = "KEY_EXISTING_PARTICIPANTS" - val KEY_CALL_URL = "KEY_CALL_URL" - val KEY_MODIFIED_BASE_URL = "KEY_MODIFIED_BASE_URL" - val KEY_NOTIFICATION_SUBJECT = "KEY_NOTIFICATION_SUBJECT" - val KEY_NOTIFICATION_SIGNATURE = "KEY_NOTIFICATION_SIGNATURE" - val KEY_INTERNAL_USER_ID = "KEY_INTERNAL_USER_ID" - val KEY_CONVERSATION_TYPE = "KEY_CONVERSATION_TYPE" - val KEY_INVITED_PARTICIPANTS = "KEY_INVITED_PARTICIPANTS" - val KEY_INVITED_CIRCLE = "KEY_INVITED_CIRCLE" - val KEY_INVITED_GROUP = "KEY_INVITED_GROUP" - val KEY_INVITED_EMAIL = "KEY_INVITED_EMAIL" - val KEY_CONVERSATION_NAME = "KEY_CONVERSATION_NAME" - val KEY_CALL_VOICE_ONLY = "KEY_CALL_VOICE_ONLY" - val KEY_CALL_WITHOUT_NOTIFICATION = "KEY_CALL_WITHOUT_NOTIFICATION" - val KEY_ACTIVE_CONVERSATION = "KEY_ACTIVE_CONVERSATION" - val KEY_SERVER_CAPABILITIES = "KEY_SERVER_CAPABILITIES" - val KEY_FROM_NOTIFICATION_START_CALL = "KEY_FROM_NOTIFICATION_START_CALL" - val KEY_ROOM_ID = "KEY_ROOM_ID" - val KEY_ARE_CALL_SOUNDS = "KEY_ARE_CALL_SOUNDS" - val KEY_BROWSER_TYPE = "KEY_BROWSER_TYPE" - val KEY_FILE_PATHS = "KEY_FILE_PATHS" - val KEY_ACCOUNT = "KEY_ACCOUNT" - val KEY_FILE_ID = "KEY_FILE_ID" - val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID" - val KEY_SHARED_TEXT = "KEY_SHARED_TEXT" - val KEY_GEOCODING_QUERY = "KEY_GEOCODING_QUERY" - val KEY_META_DATA = "KEY_META_DATA" - val KEY_FORWARD_MSG_FLAG = "KEY_FORWARD_MSG_FLAG" - val KEY_FORWARD_MSG_TEXT = "KEY_FORWARD_MSG_TEXT" - val KEY_FORWARD_HIDE_SOURCE_ROOM = "KEY_FORWARD_HIDE_SOURCE_ROOM" - val KEY_SYSTEM_NOTIFICATION_ID = "KEY_SYSTEM_NOTIFICATION_ID" + const val KEY_SELECTED_USERS = "KEY_SELECTED_USERS" + const val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS" + const val KEY_SELECTED_CIRCLES = "KEY_SELECTED_CIRCLES" + const val KEY_SELECTED_EMAILS = "KEY_SELECTED_EMAILS" + const val KEY_USERNAME = "KEY_USERNAME" + const val KEY_TOKEN = "KEY_TOKEN" + const val KEY_BASE_URL = "KEY_BASE_URL" + const val KEY_IS_ACCOUNT_IMPORT = "KEY_IS_ACCOUNT_IMPORT" + const val KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL" + const val KEY_ROOM = "KEY_CONVERSATION" + const val KEY_OPERATION_CODE = "KEY_OPERATION_CODE" + const val KEY_SHARE_INTENT = "KEY_SHARE_INTENT" + const val KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME" + const val KEY_APP_ITEM_NAME = "KEY_APP_ITEM_NAME" + const val KEY_CONVERSATION_PASSWORD = "KEY_CONVERSATION_PASSWORD" + const val KEY_ROOM_TOKEN = "KEY_ROOM_TOKEN" + const val KEY_ROOM_ONE_TO_ONE = "KEY_ROOM_ONE_TO_ONE" + const val KEY_USER_ENTITY = "KEY_USER_ENTITY" + const val KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION" + const val KEY_ADD_PARTICIPANTS = "KEY_ADD_PARTICIPANTS" + const val KEY_EXISTING_PARTICIPANTS = "KEY_EXISTING_PARTICIPANTS" + const val KEY_CALL_URL = "KEY_CALL_URL" + const val KEY_MODIFIED_BASE_URL = "KEY_MODIFIED_BASE_URL" + const val KEY_NOTIFICATION_SUBJECT = "KEY_NOTIFICATION_SUBJECT" + const val KEY_NOTIFICATION_SIGNATURE = "KEY_NOTIFICATION_SIGNATURE" + const val KEY_INTERNAL_USER_ID = "KEY_INTERNAL_USER_ID" + const val KEY_CONVERSATION_TYPE = "KEY_CONVERSATION_TYPE" + const val KEY_INVITED_PARTICIPANTS = "KEY_INVITED_PARTICIPANTS" + const val KEY_INVITED_CIRCLE = "KEY_INVITED_CIRCLE" + const val KEY_INVITED_GROUP = "KEY_INVITED_GROUP" + const val KEY_INVITED_EMAIL = "KEY_INVITED_EMAIL" + const val KEY_CONVERSATION_NAME = "KEY_CONVERSATION_NAME" + const val KEY_CALL_VOICE_ONLY = "KEY_CALL_VOICE_ONLY" + const val KEY_CALL_WITHOUT_NOTIFICATION = "KEY_CALL_WITHOUT_NOTIFICATION" + const val KEY_ACTIVE_CONVERSATION = "KEY_ACTIVE_CONVERSATION" + const val KEY_SERVER_CAPABILITIES = "KEY_SERVER_CAPABILITIES" + const val KEY_FROM_NOTIFICATION_START_CALL = "KEY_FROM_NOTIFICATION_START_CALL" + const val KEY_ROOM_ID = "KEY_ROOM_ID" + const val KEY_ARE_CALL_SOUNDS = "KEY_ARE_CALL_SOUNDS" + const val KEY_FILE_PATHS = "KEY_FILE_PATHS" + const val KEY_ACCOUNT = "KEY_ACCOUNT" + const val KEY_FILE_ID = "KEY_FILE_ID" + const val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID" + const val KEY_SHARED_TEXT = "KEY_SHARED_TEXT" + const val KEY_GEOCODING_QUERY = "KEY_GEOCODING_QUERY" + const val KEY_META_DATA = "KEY_META_DATA" + const val KEY_FORWARD_MSG_FLAG = "KEY_FORWARD_MSG_FLAG" + const val KEY_FORWARD_MSG_TEXT = "KEY_FORWARD_MSG_TEXT" + const val KEY_FORWARD_HIDE_SOURCE_ROOM = "KEY_FORWARD_HIDE_SOURCE_ROOM" + const val KEY_SYSTEM_NOTIFICATION_ID = "KEY_SYSTEM_NOTIFICATION_ID" const val KEY_MESSAGE_ID = "KEY_MESSAGE_ID" const val KEY_MIME_TYPE_FILTER = "KEY_MIME_TYPE_FILTER" + const val KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO = "KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO" + const val KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO = "KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO" } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java index a97b638bc..f8e1ef422 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java @@ -244,8 +244,8 @@ public class MagicWebSocketInstance extends WebSocketListener { shouldRefreshChat = (boolean) chatMap.get("refresh"); if (shouldRefreshChat) { HashMap<String, String> refreshChatHashMap = new HashMap<>(); - refreshChatHashMap.put(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), (String) messageHashMap.get("roomid")); - refreshChatHashMap.put(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), Long.toString(conversationUser.getId())); + refreshChatHashMap.put(BundleKeys.KEY_ROOM_TOKEN, (String) messageHashMap.get("roomid")); + refreshChatHashMap.put(BundleKeys.KEY_INTERNAL_USER_ID, Long.toString(conversationUser.getId())); eventBus.post(new WebSocketCommunicationEvent("refreshChat", refreshChatHashMap)); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6d59a36a7..9e2d4ad27 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -602,4 +602,7 @@ <string name="nc_expire_message_one_hour">1 hour</string> <string name="nc_expire_messages_explanation">Chat messages can be expired after a certain time. Note: Files shared in chat will not be deleted for the owner, but will no longer be shared in the conversation.</string> + <string name="nc_not_allowed_to_activate_audio">You\'re not allowed to activate audio!</string> + <string name="nc_not_allowed_to_activate_video">You\'re not allowed to activate video!</string> + </resources> diff --git a/app/src/test/java/com/nextcloud/talk/utils/AttendeePermissionsUtilTest.kt b/app/src/test/java/com/nextcloud/talk/utils/AttendeePermissionsUtilTest.kt deleted file mode 100644 index 6ce41bd3c..000000000 --- a/app/src/test/java/com/nextcloud/talk/utils/AttendeePermissionsUtilTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Marcel Hibbe - * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package com.nextcloud.talk.utils - -import junit.framework.TestCase -import org.junit.Test - -class AttendeePermissionsUtilTest : TestCase() { - - @Test - fun test_areFlagsSet() { - val attendeePermissionsUtil = - AttendeePermissionsUtil( - AttendeePermissionsUtil.PUBLISH_SCREEN or - AttendeePermissionsUtil.JOIN_CALL or - AttendeePermissionsUtil.DEFAULT - ) - - assert(attendeePermissionsUtil.canPublishScreen) - assert(attendeePermissionsUtil.canJoinCall) - assert(attendeePermissionsUtil.isDefault) - - assertFalse(attendeePermissionsUtil.isCustom) - assertFalse(attendeePermissionsUtil.canStartCall) - assertFalse(attendeePermissionsUtil.canIgnoreLobby) - assertFalse(attendeePermissionsUtil.canPublishAudio) - assertFalse(attendeePermissionsUtil.canPublishVideo) - } -} diff --git a/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt new file mode 100644 index 000000000..752e93fa5 --- /dev/null +++ b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt @@ -0,0 +1,57 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * @author Tim Krüger + * Copyright (C) 2022 Tim Krüger <t@timkrueger.me> + * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package com.nextcloud.talk.utils + +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.conversations.Conversation +import junit.framework.TestCase +import org.junit.Test + +class ParticipantPermissionsTest : TestCase() { + + @Test + fun test_areFlagsSet() { + + val user = User() + val conversation = Conversation() + conversation.permissions = ParticipantPermissions.PUBLISH_SCREEN or + ParticipantPermissions.JOIN_CALL or + ParticipantPermissions.DEFAULT + + val attendeePermissions = + ParticipantPermissions( + user, + conversation + ) + + assert(attendeePermissions.canPublishScreen) + assert(attendeePermissions.canJoinCall) + assert(attendeePermissions.isDefault) + + assertFalse(attendeePermissions.isCustom) + assertFalse(attendeePermissions.canStartCall()) + assertFalse(attendeePermissions.canIgnoreLobby()) + assertTrue(attendeePermissions.canPublishAudio()) + assertTrue(attendeePermissions.canPublishVideo()) + } +} |