Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/talk-android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Krüger <t@timkrueger.me>2022-09-26 14:20:43 +0300
committerGitHub <noreply@github.com>2022-09-26 14:20:43 +0300
commit9e9ee868bad206fbe43789cd299722ec2afb9285 (patch)
treebf9c02b98ba9860b4e1594fb0eab6c41a905c329
parent0fbe9eb3b0051ca3effcd513db555de45b320409 (diff)
parentc84c6445a6a9039caded58dfca307da8a8d27261 (diff)
Merge pull request #2427 from nextcloud/backport/2367/stable-15.0v15.0.0rc2
[stable-15.0] Respect participant permissions
-rw-r--r--app/src/main/java/com/nextcloud/talk/activities/CallActivity.java158
-rw-r--r--app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java14
-rw-r--r--app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt54
-rw-r--r--app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.kt15
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java12
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/CapabilitiesWorker.java2
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java4
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java4
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java34
-rw-r--r--app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java2
-rw-r--r--app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt4
-rw-r--r--app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt72
-rw-r--r--app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt107
-rw-r--r--app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt106
-rw-r--r--app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java4
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/test/java/com/nextcloud/talk/utils/AttendeePermissionsUtilTest.kt47
-rw-r--r--app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt57
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())
+ }
+}