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 2518c10bd..b7d95ec74 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -170,6 +170,8 @@ 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; @@ -293,6 +295,9 @@ public class CallActivity extends CallBaseActivity { } }); + private boolean canPublishAudioStream; + private boolean canPublishVideoStream; + @SuppressLint("ClickableViewAccessibility") @Override public void onCreate(Bundle savedInstanceState) { @@ -314,6 +319,8 @@ public class CallActivity extends CallBaseActivity { 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(KEY_FROM_NOTIFICATION_START_CALL)) { isIncomingCallFromNotification = extras.getBoolean(KEY_FROM_NOTIFICATION_START_CALL); @@ -387,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); + isPTTActive = 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); @@ -558,7 +583,7 @@ public class CallActivity extends CallBaseActivity { } } - checkPermissions(); + checkDevicePermissions(); } @Override @@ -705,7 +730,7 @@ public class CallActivity extends CallBaseActivity { } - private void checkPermissions() { + private void checkDevicePermissions() { if (isVoiceOnlyCall) { onMicrophoneClick(); } else { @@ -764,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(); } @@ -775,7 +800,7 @@ public class CallActivity extends CallBaseActivity { } } - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE) && canPublishAudioStream) { if (!microphoneOn) { onMicrophoneClick(); } @@ -888,6 +913,18 @@ public class CallActivity extends CallBaseActivity { } public void onMicrophoneClick() { + + if (isVoiceOnlyCall && !isConnectionEstablished()) { + fetchSignalingSettings(); + } + + if (!canPublishAudioStream) { + microphoneOn = false; + binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px); + // 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()) { @@ -936,11 +973,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. @@ -957,6 +989,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; @@ -1384,12 +1424,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}); @@ -1495,7 +1537,7 @@ public class CallActivity extends CallBaseActivity { private void initiateCall() { if (!TextUtils.isEmpty(roomToken)) { - checkPermissions(); + checkDevicePermissions(); } else { handleFromNotification(); } @@ -2302,7 +2344,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; 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 8b95f145a..7d1ad5870 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -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) diff --git a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt index 0d05771f9..cadb8d894 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt @@ -39,8 +39,8 @@ class ParticipantPermissions( 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 - val canPublishAudio = (conversation.permissions and PUBLISH_AUDIO) == PUBLISH_AUDIO - val canPublishVideo = (conversation.permissions and PUBLISH_VIDEO) == PUBLISH_VIDEO + 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 @@ -67,6 +67,22 @@ class ParticipantPermissions( } } + 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 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 683428bea..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 @@ -75,4 +75,6 @@ object BundleKeys { 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/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 @@ 1 hour 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. + You\'re not allowed to activate audio! + You\'re not allowed to activate video! + diff --git a/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt index 6e2a861fb..752e93fa5 100644 --- a/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt +++ b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt @@ -50,8 +50,8 @@ class ParticipantPermissionsTest : TestCase() { assertFalse(attendeePermissions.isCustom) assertFalse(attendeePermissions.canStartCall()) - assertFalse(attendeePermissions.canIgnoreLobby) - assertFalse(attendeePermissions.canPublishAudio) - assertFalse(attendeePermissions.canPublishVideo) + assertFalse(attendeePermissions.canIgnoreLobby()) + assertTrue(attendeePermissions.canPublishAudio()) + assertTrue(attendeePermissions.canPublishVideo()) } }