hook into onAnswer/onReject of CallIntegration

the Operating System shows a notification on our behalf if there is currently
a call going on that can not be put on hold (For example a Quicksy call is going
on while a Conversations call is coming on)
This commit is contained in:
Daniel Gultsch 2024-01-15 13:20:39 +01:00
parent f119c36bff
commit 6975299a28
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
3 changed files with 78 additions and 22 deletions

View file

@ -60,7 +60,7 @@ public class CallIntegration extends Connection {
@Override @Override
public void onAnswer() { public void onAnswer() {
Log.d(Config.LOGTAG, "onAnswer()"); this.callback.onCallIntegrationAnswer();
} }
@Override @Override
@ -71,12 +71,13 @@ public class CallIntegration extends Connection {
@Override @Override
public void onReject() { public void onReject() {
Log.d(Config.LOGTAG, "onReject()"); this.callback.onCallIntegrationReject();
} }
@Override @Override
public void onReject(final String replyMessage) { public void onReject(final String replyMessage) {
Log.d(Config.LOGTAG, "onReject(" + replyMessage + ")"); Log.d(Config.LOGTAG, "onReject(" + replyMessage + ")");
this.callback.onCallIntegrationReject();
} }
@RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@ -404,5 +405,9 @@ public class CallIntegration extends Connection {
void onAudioDeviceChanged( void onAudioDeviceChanged(
CallIntegration.AudioDevice selectedAudioDevice, CallIntegration.AudioDevice selectedAudioDevice,
Set<CallIntegration.AudioDevice> availableAudioDevices); Set<CallIntegration.AudioDevice> availableAudioDevices);
void onCallIntegrationReject();
void onCallIntegrationAnswer();
} }
} }

View file

@ -1109,5 +1109,15 @@ public class JingleConnectionManager extends AbstractConnectionManager {
public void onAudioDeviceChanged( public void onAudioDeviceChanged(
CallIntegration.AudioDevice selectedAudioDevice, CallIntegration.AudioDevice selectedAudioDevice,
Set<CallIntegration.AudioDevice> availableAudioDevices) {} Set<CallIntegration.AudioDevice> availableAudioDevices) {}
@Override
public void onCallIntegrationReject() {
}
@Override
public void onCallIntegrationAnswer() {
}
} }
} }

View file

@ -1,6 +1,6 @@
package eu.siacs.conversations.xmpp.jingle; package eu.siacs.conversations.xmpp.jingle;
import android.telecom.Call; import android.content.Intent;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.util.Log; import android.util.Log;
@ -35,6 +35,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.RtpSessionStatus; import eu.siacs.conversations.entities.RtpSessionStatus;
import eu.siacs.conversations.services.AppRTCAudioManager; import eu.siacs.conversations.services.AppRTCAudioManager;
import eu.siacs.conversations.services.CallIntegration; import eu.siacs.conversations.services.CallIntegration;
import eu.siacs.conversations.ui.RtpSessionActivity;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.Jid;
@ -75,7 +76,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
private static final long BUSY_TIME_OUT = 30; private static final long BUSY_TIME_OUT = 30;
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this); private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
private final Queue<Map.Entry<String, DescriptionTransport<RtpDescription,IceUdpTransportInfo>>> private final Queue<
Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>>
pendingIceCandidates = new LinkedList<>(); pendingIceCandidates = new LinkedList<>();
private final OmemoVerification omemoVerification = new OmemoVerification(); private final OmemoVerification omemoVerification = new OmemoVerification();
private final CallIntegration callIntegration; private final CallIntegration callIntegration;
@ -91,13 +93,28 @@ public class JingleRtpConnection extends AbstractJingleConnection
private final Queue<PeerConnection.PeerConnectionState> stateHistory = new LinkedList<>(); private final Queue<PeerConnection.PeerConnectionState> stateHistory = new LinkedList<>();
private ScheduledFuture<?> ringingTimeoutFuture; private ScheduledFuture<?> ringingTimeoutFuture;
JingleRtpConnection(final JingleConnectionManager jingleConnectionManager, final Id id, final Jid initiator) { JingleRtpConnection(
this(jingleConnectionManager, id, initiator, new CallIntegration(jingleConnectionManager.getXmppConnectionService().getApplicationContext())); final JingleConnectionManager jingleConnectionManager,
this.callIntegration.setAddress(CallIntegration.address(id.with.asBareJid()), TelecomManager.PRESENTATION_ALLOWED); final Id id,
final Jid initiator) {
this(
jingleConnectionManager,
id,
initiator,
new CallIntegration(
jingleConnectionManager
.getXmppConnectionService()
.getApplicationContext()));
this.callIntegration.setAddress(
CallIntegration.address(id.with.asBareJid()), TelecomManager.PRESENTATION_ALLOWED);
this.callIntegration.setInitialized(); this.callIntegration.setInitialized();
} }
JingleRtpConnection(final JingleConnectionManager jingleConnectionManager, final Id id, final Jid initiator, final CallIntegration callIntegration) { JingleRtpConnection(
final JingleConnectionManager jingleConnectionManager,
final Id id,
final Jid initiator,
final CallIntegration callIntegration) {
super(jingleConnectionManager, id, initiator); super(jingleConnectionManager, id, initiator);
final Conversation conversation = final Conversation conversation =
jingleConnectionManager jingleConnectionManager
@ -231,8 +248,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
private void receiveTransportInfo( private void receiveTransportInfo(
final JinglePacket jinglePacket, final RtpContentMap contentMap) { final JinglePacket jinglePacket, final RtpContentMap contentMap) {
final Set<Map.Entry<String, DescriptionTransport<RtpDescription,IceUdpTransportInfo>>> candidates = final Set<Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>>
contentMap.contents.entrySet(); candidates = contentMap.contents.entrySet();
final RtpContentMap remote = getRemoteContentMap(); final RtpContentMap remote = getRemoteContentMap();
final Set<String> remoteContentIds = final Set<String> remoteContentIds =
remote == null ? Collections.emptySet() : remote.contents.keySet(); remote == null ? Collections.emptySet() : remote.contents.keySet();
@ -1004,14 +1021,17 @@ public class JingleRtpConnection extends AbstractJingleConnection
} }
private void processCandidates( private void processCandidates(
final Set<Map.Entry<String, DescriptionTransport<RtpDescription,IceUdpTransportInfo>>> contents) { final Set<Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>>
for (final Map.Entry<String, DescriptionTransport<RtpDescription,IceUdpTransportInfo>> content : contents) { contents) {
for (final Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>
content : contents) {
processCandidate(content); processCandidate(content);
} }
} }
private void processCandidate( private void processCandidate(
final Map.Entry<String, DescriptionTransport<RtpDescription,IceUdpTransportInfo>> content) { final Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>
content) {
final RtpContentMap rtpContentMap = getRemoteContentMap(); final RtpContentMap rtpContentMap = getRemoteContentMap();
final List<String> indices = toIdentificationTags(rtpContentMap); final List<String> indices = toIdentificationTags(rtpContentMap);
final String sdpMid = content.getKey(); // aka content name final String sdpMid = content.getKey(); // aka content name
@ -1960,12 +1980,10 @@ public class JingleRtpConnection extends AbstractJingleConnection
sendSessionTerminate(reason, null); sendSessionTerminate(reason, null);
} }
protected void sendSessionTerminate(final Reason reason, final String text) { protected void sendSessionTerminate(final Reason reason, final String text) {
sendSessionTerminate(reason, text, this::writeLogMessage); sendSessionTerminate(reason, text, this::writeLogMessage);
} }
private void sendTransportInfo( private void sendTransportInfo(
final String contentName, IceUdpTransportInfo.Candidate candidate) { final String contentName, IceUdpTransportInfo.Candidate candidate) {
final RtpContentMap transportInfo; final RtpContentMap transportInfo;
@ -2351,7 +2369,6 @@ public class JingleRtpConnection extends AbstractJingleConnection
sendSessionAccept(); sendSessionAccept();
} }
@Override @Override
protected synchronized boolean transition(final State target, final Runnable runnable) { protected synchronized boolean transition(final State target, final Runnable runnable) {
if (super.transition(target, runnable)) { if (super.transition(target, runnable)) {
@ -2592,7 +2609,6 @@ public class JingleRtpConnection extends AbstractJingleConnection
private void modifyLocalContentMap(final RtpContentMap rtpContentMap) { private void modifyLocalContentMap(final RtpContentMap rtpContentMap) {
final RtpContentMap activeContents = rtpContentMap.activeContents(); final RtpContentMap activeContents = rtpContentMap.activeContents();
setLocalContentMap(activeContents); setLocalContentMap(activeContents);
// TODO change audio device on callIntegration was (`switchSpeakerPhonePreference(AppRTCAudioManager.SpeakerPhonePreference.of(activeContents.getMedia())`)
updateEndUserState(); updateEndUserState();
} }
@ -2625,7 +2641,6 @@ public class JingleRtpConnection extends AbstractJingleConnection
return this.sessionDuration.elapsed(TimeUnit.MILLISECONDS); return this.sessionDuration.elapsed(TimeUnit.MILLISECONDS);
} }
public CallIntegration getCallIntegration() { public CallIntegration getCallIntegration() {
return this.callIntegration; return this.callIntegration;
} }
@ -2673,11 +2688,37 @@ public class JingleRtpConnection extends AbstractJingleConnection
} }
} }
@Override
public void onCallIntegrationReject() {
Log.d(Config.LOGTAG, "rejecting call from system notification / call integration");
try {
rejectCall();
} catch (final IllegalStateException e) {
Log.w(Config.LOGTAG, "race condition on rejecting call from notification", e);
}
}
@Override
public void onCallIntegrationAnswer() {
// we need to start the UI to a) show it and b) be able to ask for permissions
final Intent intent = new Intent(xmppConnectionService, RtpSessionActivity.class);
intent.setAction(RtpSessionActivity.ACTION_ACCEPT_CALL);
intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().toEscapedString());
intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
Log.d(Config.LOGTAG, "start activity to accept call from call integration");
xmppConnectionService.startActivity(intent);
}
@Override @Override
public void onAudioDeviceChanged( public void onAudioDeviceChanged(
final CallIntegration.AudioDevice selectedAudioDevice, final CallIntegration.AudioDevice selectedAudioDevice,
final Set<CallIntegration.AudioDevice> availableAudioDevices) { final Set<CallIntegration.AudioDevice> availableAudioDevices) {
Log.d(Config.LOGTAG,"onAudioDeviceChanged("+selectedAudioDevice+","+availableAudioDevices+")"); Log.d(
Config.LOGTAG,
"onAudioDeviceChanged(" + selectedAudioDevice + "," + availableAudioDevices + ")");
xmppConnectionService.notifyJingleRtpConnectionUpdate( xmppConnectionService.notifyJingleRtpConnectionUpdate(
selectedAudioDevice, availableAudioDevices); selectedAudioDevice, availableAudioDevices);
} }