Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Checkbox
import androidx.compose.material.CheckboxDefaults
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.RadioButton
import androidx.compose.material.RadioButtonDefaults
Expand Down Expand Up @@ -135,7 +137,7 @@ private fun Body(
toggleUserSelection: (Int) -> Unit,
onStartCallClick: (cid: StreamCallId, membersList: String, joinAndRing: Boolean) -> Unit,
) {
var callerJoinsFirst by rememberSaveable { mutableStateOf(false) }
var callerJoinsFirst by rememberSaveable { mutableStateOf(true) }

Box(
modifier = Modifier
Expand Down Expand Up @@ -164,9 +166,18 @@ private fun Body(
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text("Join First", color = Color.White)
Checkbox(callerJoinsFirst, onCheckedChange = {
callerJoinsFirst = !callerJoinsFirst
})
Checkbox(
callerJoinsFirst,
modifier = Modifier.offset(x = 10.dp),
colors = CheckboxDefaults.colors(
uncheckedColor = Color.White, // Border color when unchecked
checkedColor = Color.White, // Fill color when checked
checkmarkColor = VideoTheme.colors.buttonBrandDefault, // Tick color
),
onCheckedChange = {
callerJoinsFirst = !callerJoinsFirst
},
)
}
UserList(
entries = users,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package io.getstream.video.android.core

import android.app.Notification
import android.os.Bundle
import android.util.Log
import androidx.compose.runtime.Stable
import androidx.core.app.NotificationManagerCompat
import io.getstream.android.video.generated.models.BlockedUserEvent
Expand Down Expand Up @@ -160,6 +159,7 @@ import java.util.Locale
import java.util.SortedMap
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import kotlin.time.Duration
import kotlin.time.DurationUnit
Expand Down Expand Up @@ -1023,7 +1023,7 @@ public class CallState(
is JoinCallResponseEvent -> {
// time to update call state based on the join response
updateFromJoinResponse(event)
if (!ringingStateUpdatesStopped) {
if (!ringingStateUpdatesStopped.get()) {
updateRingingState()
} else {
_ringingState.value = RingingState.Outgoing(acceptedByCallee = true)
Expand Down Expand Up @@ -1239,6 +1239,7 @@ public class CallState(
}

private fun updateRingingState(rejectReason: RejectReason? = null) {
val ringingStateLogger by taggedLogger("RingingState")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ringingStateLogger is created inside updateRingingState() via delegate — this allocates a new logger on every call. This method fires frequently during call state changes. Should be a class-level property like the existing logger.

if (ringingState.value == RingingState.RejectedByAll) {
return
}
Expand All @@ -1256,8 +1257,9 @@ public class CallState(
val userIsParticipant =
_session.value?.participants?.find { it.user.id == client.userId } != null
val outgoingMembersCount = _members.value.filter { it.value.user.id != client.userId }.size
val createdBySelf = createdBy?.id == client.userId

Log.d("RingingState", "Current: ${_ringingState.value}, call_id: ${call.cid}")
ringingStateLogger.d { "Current: ${_ringingState.value}, call_id: ${call.cid}" }

val ringingStateLogs = arrayListOf(
("acceptedByMe: $isAcceptedByMe"),
Expand All @@ -1268,19 +1270,19 @@ public class CallState(
("userIsParticipant: $userIsParticipant"),
).joinToString("") { it + "\n" }

Log.d(
"RingingState",
"call_id: ${call.cid}, Flags: $ringingStateLogs",
)
ringingStateLogger.d { "call_id: ${call.cid}, Flags: $ringingStateLogs" }

// no members - call is empty, we can join
val state: RingingState = if (hasActiveCall && !ringingStateUpdatesStopped) {
val state: RingingState = if (hasActiveCall && !ringingStateUpdatesStopped.get()) {
cancelTimeout()
RingingState.Active
} else if (isRejectedByMe) {
call.leave("updateRingingState-rejected-self")
cancelTimeout()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The // for joinAndRing comment is unclear — doesn't explain why this branch exists alongside the first hasActiveCall check above.

RingingState.RejectedByAll
} else if (hasActiveCall && createdBySelf && acceptedBy.isNotEmpty() && !isAcceptedByMe) { // for joinAndRing
cancelTimeout()
RingingState.Active
} else if ((rejectedBy.isNotEmpty() && rejectedBy.size >= outgoingMembersCount) ||
(rejectedBy.contains(createdBy?.id) && hasRingingCall)
) {
Expand All @@ -1303,7 +1305,7 @@ public class CallState(
}
} else if (hasRingingCall && createdBy?.id == client.userId) {
// The call is created by us
logger.d { "acceptedBy: $acceptedBy, userIsParticipant: $userIsParticipant" }
ringingStateLogger.d { "acceptedBy: $acceptedBy, userIsParticipant: $userIsParticipant" }
if (acceptedBy.isEmpty()) {
// no one accepted the call
RingingState.Outgoing(acceptedByCallee = false)
Expand All @@ -1312,8 +1314,9 @@ public class CallState(
RingingState.Outgoing(acceptedByCallee = true)
} else {
// call is accepted and we are already in the call
ringingStateUpdatesStopped = false
ringingStateUpdatesStopped.set(false)
cancelTimeout()
logger.d { "RingingState.Active source 3" }
RingingState.Active
}
} else {
Expand All @@ -1325,7 +1328,7 @@ public class CallState(
}

if (_ringingState.value != state) {
logger.d { "Updating ringing state ${_ringingState.value} -> $state" }
ringingStateLogger.d { "Updating ringing state ${_ringingState.value} -> $state" }

// handle the auto-cancel for outgoing ringing calls
if (state is RingingState.Outgoing && !state.acceptedByCallee) {
Expand All @@ -1338,7 +1341,7 @@ public class CallState(

// stop the call ringing timer if it's running
}
Log.d("RingingState", "Update: $state")
ringingStateLogger.d { "Update: $state" }

_ringingState.value = state
}
Expand Down Expand Up @@ -1394,7 +1397,7 @@ public class CallState(

// double check that we are still in Outgoing call state and call is not active
if (_ringingState.value is RingingState.Outgoing || _ringingState.value is RingingState.Incoming && client.state.activeCall.value == null) {
ringingStateUpdatesStopped = false
ringingStateUpdatesStopped.set(false)
call.reject(reason = RejectReason.Custom(alias = REJECT_REASON_TIMEOUT))
call.leave("start-ringing-timeout")
}
Expand Down Expand Up @@ -1643,10 +1646,10 @@ public class CallState(
_broadcasting.value = true
}

private var ringingStateUpdatesStopped = false
private var ringingStateUpdatesStopped = AtomicBoolean(false)

internal fun toggleRingingStateUpdates(stopped: Boolean) {
ringingStateUpdatesStopped = stopped
ringingStateUpdatesStopped.set(stopped)
}

/**
Expand Down
Loading