diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index febe12b14..da3628b6f 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -121,6 +121,8 @@ public final class Config {
false; // disables STUN/TURN and Proxy65 look up (useful to debug IBB fallback)
public static final boolean USE_DIRECT_JINGLE_CANDIDATES = true;
public static final boolean USE_JINGLE_MESSAGE_INIT = true;
+
+ public static final boolean JINGLE_MESSAGE_INIT_STRICT_OFFLINE_CHECK = false;
public static final boolean DISABLE_HTTP_UPLOAD = false;
public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts
public static final boolean BACKGROUND_STANZA_LOGGING =
diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java
index 59480b0ce..d3bd706f8 100644
--- a/src/main/java/eu/siacs/conversations/entities/Presences.java
+++ b/src/main/java/eu/siacs/conversations/entities/Presences.java
@@ -83,6 +83,12 @@ public class Presences {
}
}
+ public boolean isEmpty() {
+ synchronized (this.presences) {
+ return this.presences.isEmpty();
+ }
+ }
+
public String[] toResourceArray() {
synchronized (this.presences) {
final String[] presencesArray = new String[presences.size()];
diff --git a/src/main/java/eu/siacs/conversations/services/CallIntegration.java b/src/main/java/eu/siacs/conversations/services/CallIntegration.java
index 489d71256..f07ebe28d 100644
--- a/src/main/java/eu/siacs/conversations/services/CallIntegration.java
+++ b/src/main/java/eu/siacs/conversations/services/CallIntegration.java
@@ -303,6 +303,7 @@ public class CallIntegration extends Connection {
@Override
public void onStateChanged(final int state) {
Log.d(Config.LOGTAG, "onStateChanged(" + state + ")");
+ // TODO devices before selfManaged() will likely have to play their own ringback sound
if (state == STATE_ACTIVE) {
playConnectedSound();
} else if (state == STATE_DISCONNECTED) {
diff --git a/src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java b/src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java
index 99f565ff1..de39abb51 100644
--- a/src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java
@@ -97,15 +97,26 @@ public class CallIntegrationConnectionService extends ConnectionService {
intent.putExtra(RtpSessionActivity.EXTRA_WITH, with.toEscapedString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- final CallIntegration callIntegration;
+ final Connection callIntegration;
if (with.isBareJid()) {
- final var proposal =
- service.getJingleConnectionManager()
- .proposeJingleRtpSession(account, with, media);
-
- intent.putExtra(
- RtpSessionActivity.EXTRA_LAST_REPORTED_STATE,
- RtpEndUserState.FINDING_DEVICE.toString());
+ final var contact = account.getRoster().getContact(with);
+ if (Config.JINGLE_MESSAGE_INIT_STRICT_OFFLINE_CHECK
+ && contact.getPresences().isEmpty()) {
+ intent.putExtra(
+ RtpSessionActivity.EXTRA_LAST_REPORTED_STATE,
+ RtpEndUserState.CONTACT_OFFLINE.toString());
+ callIntegration =
+ Connection.createFailedConnection(
+ new DisconnectCause(DisconnectCause.ERROR, "contact is offline"));
+ } else {
+ final var proposal =
+ service.getJingleConnectionManager()
+ .proposeJingleRtpSession(account, with, media);
+ intent.putExtra(
+ RtpSessionActivity.EXTRA_LAST_REPORTED_STATE,
+ RtpEndUserState.FINDING_DEVICE.toString());
+ callIntegration = proposal.getCallIntegration();
+ }
if (Media.audioOnly(media)) {
intent.putExtra(
RtpSessionActivity.EXTRA_LAST_ACTION,
@@ -115,7 +126,6 @@ public class CallIntegrationConnectionService extends ConnectionService {
RtpSessionActivity.EXTRA_LAST_ACTION,
RtpSessionActivity.ACTION_MAKE_VIDEO_CALL);
}
- callIntegration = proposal.getCallIntegration();
} else {
final JingleRtpConnection jingleRtpConnection =
service.getJingleConnectionManager().initializeRtpSession(account, with, media);
diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
index c40a49a72..ee0770023 100644
--- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
@@ -95,6 +95,7 @@ public class RtpSessionActivity extends XmppActivity
RtpEndUserState.APPLICATION_ERROR,
RtpEndUserState.SECURITY_ERROR,
RtpEndUserState.DECLINED_OR_BUSY,
+ RtpEndUserState.CONTACT_OFFLINE,
RtpEndUserState.CONNECTIVITY_ERROR,
RtpEndUserState.CONNECTIVITY_LOST_ERROR,
RtpEndUserState.RETRACTED);
@@ -881,6 +882,7 @@ public class RtpSessionActivity extends XmppActivity
case FINDING_DEVICE -> setTitle(R.string.rtp_state_finding_device);
case RINGING -> setTitle(R.string.rtp_state_ringing);
case DECLINED_OR_BUSY -> setTitle(R.string.rtp_state_declined_or_busy);
+ case CONTACT_OFFLINE -> setTitle(R.string.rtp_state_contact_offline);
case CONNECTIVITY_ERROR -> setTitle(R.string.rtp_state_connectivity_error);
case CONNECTIVITY_LOST_ERROR -> setTitle(R.string.rtp_state_connectivity_lost_error);
case RETRACTED -> setTitle(R.string.rtp_state_retracted);
@@ -974,7 +976,8 @@ public class RtpSessionActivity extends XmppActivity
this.binding.acceptCall.setOnClickListener((v -> acceptContentAdd(contentAddition)));
this.binding.acceptCall.setImageResource(R.drawable.ic_baseline_check_24);
this.binding.acceptCall.setVisibility(View.VISIBLE);
- } else if (state == RtpEndUserState.DECLINED_OR_BUSY) {
+ } else if (asList(RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONTACT_OFFLINE)
+ .contains(state)) {
this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java
index 885820460..fff82031a 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpEndUserState.java
@@ -1,20 +1,23 @@
package eu.siacs.conversations.xmpp.jingle;
public enum RtpEndUserState {
- INCOMING_CALL, //received a 'propose' message
- CONNECTING, //session-initiate or session-accepted but no webrtc peer connection yet
- CONNECTED, //session-accepted and webrtc peer connection is connected
- RECONNECTING, //session-accepted and webrtc peer connection was connected once but is currently disconnected or failed
- INCOMING_CONTENT_ADD, //session-accepted with a pending, incoming content-add
- FINDING_DEVICE, //'propose' has been sent out; no 184 ack yet
- RINGING, //'propose' has been sent out and it has been 184 acked
- ACCEPTING_CALL, //'proceed' message has been sent; but no session-initiate has been received
- ENDING_CALL, //libwebrt says 'closed' but session-terminate has not gone through
- ENDED, //close UI
- DECLINED_OR_BUSY, //other party declined; no retry button
- CONNECTIVITY_ERROR, //network error; retry button
- CONNECTIVITY_LOST_ERROR, //network error but for call duration > 0
- RETRACTED, //user pressed home or power button during 'ringing' - shows retry button
- APPLICATION_ERROR, //something rather bad happened; libwebrtc failed or we got in IQ-error
- SECURITY_ERROR //problem with DTLS (missing) or verification
+ INCOMING_CALL, // received a 'propose' message
+ CONNECTING, // session-initiate or session-accepted but no webrtc peer connection yet
+ CONNECTED, // session-accepted and webrtc peer connection is connected
+ RECONNECTING, // session-accepted and webrtc peer connection was connected once but is currently
+ // disconnected or failed
+ INCOMING_CONTENT_ADD, // session-accepted with a pending, incoming content-add
+ FINDING_DEVICE, // 'propose' has been sent out; no 184 ack yet
+ RINGING, // 'propose' has been sent out and it has been 184 acked
+ ACCEPTING_CALL, // 'proceed' message has been sent; but no session-initiate has been received
+ ENDING_CALL, // libwebrt says 'closed' but session-terminate has not gone through
+ ENDED, // close UI
+ DECLINED_OR_BUSY, // other party declined; no retry button
+ CONTACT_OFFLINE, // when `JINGLE_MESSAGE_INIT_STRICT_OFFLINE_CHECK` is true this shows up when
+ // the contact is offline, generally similar to BUSY
+ CONNECTIVITY_ERROR, // network error; retry button
+ CONNECTIVITY_LOST_ERROR, // network error but for call duration > 0
+ RETRACTED, // user pressed home or power button during 'ringing' - shows retry button
+ APPLICATION_ERROR, // something rather bad happened; libwebrtc failed or we got in IQ-error
+ SECURITY_ERROR // problem with DTLS (missing) or verification
}
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 996977eab..f47731d06 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -929,6 +929,7 @@
Discovering devices
Ringing
Busy
+ Contact is not available
Could not connect call
Connection lost
Retracted call