show speaker selection during 'ringing'
This commit is contained in:
parent
bff1ac5ebc
commit
bfe2aff7a1
|
@ -63,6 +63,7 @@ import eu.siacs.conversations.xmpp.jingle.ContentAddition;
|
||||||
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
|
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
|
||||||
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
|
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
|
||||||
import eu.siacs.conversations.xmpp.jingle.Media;
|
import eu.siacs.conversations.xmpp.jingle.Media;
|
||||||
|
import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
|
||||||
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
|
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
|
||||||
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
|
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
|
||||||
|
|
||||||
|
@ -117,6 +118,13 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
RtpEndUserState.ACCEPTING_CALL,
|
RtpEndUserState.ACCEPTING_CALL,
|
||||||
RtpEndUserState.CONNECTING,
|
RtpEndUserState.CONNECTING,
|
||||||
RtpEndUserState.RECONNECTING);
|
RtpEndUserState.RECONNECTING);
|
||||||
|
private static final List<RtpEndUserState> STATES_SHOWING_SPEAKER_CONFIGURATION =
|
||||||
|
new ImmutableList.Builder<RtpEndUserState>()
|
||||||
|
.add(RtpEndUserState.FINDING_DEVICE)
|
||||||
|
.add(RtpEndUserState.RINGING)
|
||||||
|
.add(RtpEndUserState.CONNECTING)
|
||||||
|
.addAll(STATES_CONSIDERED_CONNECTED)
|
||||||
|
.build();
|
||||||
private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session";
|
private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session";
|
||||||
private static final int REQUEST_ACCEPT_CALL = 0x1111;
|
private static final int REQUEST_ACCEPT_CALL = 0x1111;
|
||||||
private static final int REQUEST_ACCEPT_CONTENT = 0x1112;
|
private static final int REQUEST_ACCEPT_CONTENT = 0x1112;
|
||||||
|
@ -139,8 +147,13 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
public static Set<Media> actionToMedia(final String action) {
|
public static Set<Media> actionToMedia(final String action) {
|
||||||
if (ACTION_MAKE_VIDEO_CALL.equals(action)) {
|
if (ACTION_MAKE_VIDEO_CALL.equals(action)) {
|
||||||
return ImmutableSet.of(Media.AUDIO, Media.VIDEO);
|
return ImmutableSet.of(Media.AUDIO, Media.VIDEO);
|
||||||
} else {
|
} else if (ACTION_MAKE_VOICE_CALL.equals(action)) {
|
||||||
return ImmutableSet.of(Media.AUDIO);
|
return ImmutableSet.of(Media.AUDIO);
|
||||||
|
} else {
|
||||||
|
Log.w(
|
||||||
|
Config.LOGTAG,
|
||||||
|
"actionToMedia can not get media set from unknown action " + action);
|
||||||
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,14 +287,15 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
private void retractSessionProposal() {
|
private void retractSessionProposal() {
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION);
|
||||||
final Account account = extractAccount(intent);
|
final Account account = extractAccount(intent);
|
||||||
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
|
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
|
||||||
final String state = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
|
final String state = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
|
||||||
if (!Intent.ACTION_VIEW.equals(action)
|
if (!Intent.ACTION_VIEW.equals(action)
|
||||||
|| state == null
|
|| state == null
|
||||||
|| !END_CARD.contains(RtpEndUserState.valueOf(state))) {
|
|| !END_CARD.contains(RtpEndUserState.valueOf(state))) {
|
||||||
resetIntent(
|
final Set<Media> media = actionToMedia(lastAction == null ? action : lastAction);
|
||||||
account, with, RtpEndUserState.RETRACTED, actionToMedia(intent.getAction()));
|
resetIntent(account, with, RtpEndUserState.RETRACTED, media);
|
||||||
}
|
}
|
||||||
xmppConnectionService
|
xmppConnectionService
|
||||||
.getJingleConnectionManager()
|
.getJingleConnectionManager()
|
||||||
|
@ -1049,6 +1063,14 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
} else {
|
} else {
|
||||||
this.binding.inCallActionLeft.setVisibility(View.GONE);
|
this.binding.inCallActionLeft.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
} else if (STATES_SHOWING_SPEAKER_CONFIGURATION.contains(state)
|
||||||
|
&& !isPictureInPicture()
|
||||||
|
&& Media.audioOnly(media)) {
|
||||||
|
final CallIntegration callIntegration = requireCallIntegration();
|
||||||
|
updateInCallButtonConfigurationSpeaker(
|
||||||
|
callIntegration.getSelectedAudioDevice(),
|
||||||
|
callIntegration.getAudioDevices().size());
|
||||||
|
this.binding.inCallActionFarRight.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
this.binding.inCallActionLeft.setVisibility(View.GONE);
|
this.binding.inCallActionLeft.setVisibility(View.GONE);
|
||||||
this.binding.inCallActionRight.setVisibility(View.GONE);
|
this.binding.inCallActionRight.setVisibility(View.GONE);
|
||||||
|
@ -1297,17 +1319,13 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToEarpiece(View view) {
|
private void switchToEarpiece(final View view) {
|
||||||
requireRtpConnection()
|
requireCallIntegration().setAudioDevice(CallIntegration.AudioDevice.EARPIECE);
|
||||||
.getCallIntegration()
|
|
||||||
.setAudioDevice(CallIntegration.AudioDevice.EARPIECE);
|
|
||||||
acquireProximityWakeLock();
|
acquireProximityWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToSpeaker(View view) {
|
private void switchToSpeaker(final View view) {
|
||||||
requireRtpConnection()
|
requireCallIntegration().setAudioDevice(CallIntegration.AudioDevice.SPEAKER_PHONE);
|
||||||
.getCallIntegration()
|
|
||||||
.setAudioDevice(CallIntegration.AudioDevice.SPEAKER_PHONE);
|
|
||||||
releaseProximityWakeLock();
|
releaseProximityWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,6 +1377,33 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CallIntegration requireCallIntegration() {
|
||||||
|
return requireOngoingRtpSession().getCallIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
private OngoingRtpSession requireOngoingRtpSession() {
|
||||||
|
final JingleRtpConnection connection =
|
||||||
|
this.rtpConnectionReference != null ? this.rtpConnectionReference.get() : null;
|
||||||
|
if (connection != null) {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
final Intent currentIntent = getIntent();
|
||||||
|
final String withExtra =
|
||||||
|
currentIntent == null ? null : currentIntent.getStringExtra(EXTRA_WITH);
|
||||||
|
final var account = extractAccount(currentIntent);
|
||||||
|
if (withExtra == null) {
|
||||||
|
throw new IllegalStateException("Current intent has no EXTRA_WITH");
|
||||||
|
}
|
||||||
|
final var matching =
|
||||||
|
xmppConnectionService
|
||||||
|
.getJingleConnectionManager()
|
||||||
|
.matchingProposal(account, Jid.of(withExtra));
|
||||||
|
if (matching.isPresent()) {
|
||||||
|
return matching.get();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("No matching session proposal");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onJingleRtpConnectionUpdate(
|
public void onJingleRtpConnectionUpdate(
|
||||||
Account account, Jid with, final String sessionId, RtpEndUserState state) {
|
Account account, Jid with, final String sessionId, RtpEndUserState state) {
|
||||||
|
@ -1425,16 +1470,23 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
+ ", available:"
|
+ ", available:"
|
||||||
+ availableAudioDevices);
|
+ availableAudioDevices);
|
||||||
try {
|
try {
|
||||||
final RtpEndUserState endUserState = requireRtpConnection().getEndUserState();
|
final OngoingRtpSession ongoingRtpSession = requireOngoingRtpSession();
|
||||||
final Set<Media> media = getMedia();
|
final RtpEndUserState endUserState;
|
||||||
|
if (ongoingRtpSession instanceof JingleRtpConnection jingleRtpConnection) {
|
||||||
|
endUserState = jingleRtpConnection.getEndUserState();
|
||||||
|
} else {
|
||||||
|
// for session proposals all end user states are functionally the same
|
||||||
|
endUserState = RtpEndUserState.RINGING;
|
||||||
|
}
|
||||||
|
final Set<Media> media = ongoingRtpSession.getMedia();
|
||||||
if (END_CARD.contains(endUserState)) {
|
if (END_CARD.contains(endUserState)) {
|
||||||
Log.d(
|
Log.d(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
"onAudioDeviceChanged() nothing to do because end card has been reached");
|
"onAudioDeviceChanged() nothing to do because end card has been reached");
|
||||||
} else {
|
} else {
|
||||||
if (Media.audioOnly(media) && endUserState == RtpEndUserState.CONNECTED) {
|
if (Media.audioOnly(media)
|
||||||
final CallIntegration callIntegration =
|
&& STATES_SHOWING_SPEAKER_CONFIGURATION.contains(endUserState)) {
|
||||||
requireRtpConnection().getCallIntegration();
|
final CallIntegration callIntegration = requireCallIntegration();
|
||||||
updateInCallButtonConfigurationSpeaker(
|
updateInCallButtonConfigurationSpeaker(
|
||||||
callIntegration.getSelectedAudioDevice(),
|
callIntegration.getSelectedAudioDevice(),
|
||||||
callIntegration.getAudioDevices().size());
|
callIntegration.getAudioDevices().size());
|
||||||
|
@ -1457,16 +1509,17 @@ public class RtpSessionActivity extends XmppActivity
|
||||||
if (withExtra == null) {
|
if (withExtra == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final Set<Media> media = actionToMedia(currentIntent.getStringExtra(EXTRA_LAST_ACTION));
|
||||||
if (Jid.ofEscaped(withExtra).asBareJid().equals(with)) {
|
if (Jid.ofEscaped(withExtra).asBareJid().equals(with)) {
|
||||||
runOnUiThread(
|
runOnUiThread(
|
||||||
() -> {
|
() -> {
|
||||||
updateVerifiedShield(false);
|
updateVerifiedShield(false);
|
||||||
updateStateDisplay(state);
|
updateStateDisplay(state);
|
||||||
updateButtonConfiguration(state);
|
updateButtonConfiguration(state, media, null);
|
||||||
updateIncomingCallScreen(state);
|
updateIncomingCallScreen(state);
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
});
|
});
|
||||||
resetIntent(account, with, state, actionToMedia(currentIntent.getAction()));
|
resetIntent(account, with, state, media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,8 +219,7 @@ public abstract class AbstractJingleConnection {
|
||||||
if (isTerminated()) {
|
if (isTerminated()) {
|
||||||
this.jingleConnectionManager.finishConnectionOrThrow(this);
|
this.jingleConnectionManager.finishConnectionOrThrow(this);
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError(
|
throw new AssertionError(String.format("Unable to call finish from %s", this.state));
|
||||||
String.format("Unable to call finish from %s", this.state));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +347,7 @@ public abstract class AbstractJingleConnection {
|
||||||
return features != null && features.contains(feature);
|
return features != null && features.contains(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Id implements OngoingRtpSession {
|
public static class Id {
|
||||||
public final Account account;
|
public final Account account;
|
||||||
public final Jid with;
|
public final Jid with;
|
||||||
public final String sessionId;
|
public final String sessionId;
|
||||||
|
@ -400,17 +399,14 @@ public abstract class AbstractJingleConnection {
|
||||||
return Objects.hashCode(account.getUuid(), with, sessionId);
|
return Objects.hashCode(account.getUuid(), with, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Account getAccount() {
|
public Account getAccount() {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Jid getWith() {
|
public Jid getWith() {
|
||||||
return with;
|
return with;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSessionId() {
|
public String getSessionId() {
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,11 +601,11 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
public Optional<OngoingRtpSession> getOngoingRtpConnection(final Contact contact) {
|
public Optional<OngoingRtpSession> getOngoingRtpConnection(final Contact contact) {
|
||||||
for (final Map.Entry<AbstractJingleConnection.Id, AbstractJingleConnection> entry :
|
for (final Map.Entry<AbstractJingleConnection.Id, AbstractJingleConnection> entry :
|
||||||
this.connections.entrySet()) {
|
this.connections.entrySet()) {
|
||||||
if (entry.getValue() instanceof JingleRtpConnection) {
|
if (entry.getValue() instanceof JingleRtpConnection jingleRtpConnection) {
|
||||||
final AbstractJingleConnection.Id id = entry.getKey();
|
final AbstractJingleConnection.Id id = entry.getKey();
|
||||||
if (id.account == contact.getAccount()
|
if (id.account == contact.getAccount()
|
||||||
&& id.with.asBareJid().equals(contact.getJid().asBareJid())) {
|
&& id.with.asBareJid().equals(contact.getJid().asBareJid())) {
|
||||||
return Optional.of(id);
|
return Optional.of(jingleRtpConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,9 +765,22 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
mXmppConnectionService.sendMessagePacket(account, messagePacket);
|
mXmppConnectionService.sendMessagePacket(account, messagePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<RtpSessionProposal> matchingProposal(final Account account, final Jid with) {
|
||||||
|
synchronized (this.rtpSessionProposals) {
|
||||||
|
for (final Map.Entry<RtpSessionProposal, DeviceDiscoveryState> entry :
|
||||||
|
this.rtpSessionProposals.entrySet()) {
|
||||||
|
final RtpSessionProposal proposal = entry.getKey();
|
||||||
|
if (proposal.account == account && with.asBareJid().equals(proposal.with)) {
|
||||||
|
return Optional.of(proposal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasMatchingProposal(final Account account, final Jid with) {
|
public boolean hasMatchingProposal(final Account account, final Jid with) {
|
||||||
synchronized (this.rtpSessionProposals) {
|
synchronized (this.rtpSessionProposals) {
|
||||||
for (Map.Entry<RtpSessionProposal, DeviceDiscoveryState> entry :
|
for (final Map.Entry<RtpSessionProposal, DeviceDiscoveryState> entry :
|
||||||
this.rtpSessionProposals.entrySet()) {
|
this.rtpSessionProposals.entrySet()) {
|
||||||
final var state = entry.getValue();
|
final var state = entry.getValue();
|
||||||
final RtpSessionProposal proposal = entry.getKey();
|
final RtpSessionProposal proposal = entry.getKey();
|
||||||
|
@ -1102,9 +1115,15 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CallIntegration getCallIntegration() {
|
public CallIntegration getCallIntegration() {
|
||||||
return this.callIntegration;
|
return this.callIntegration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Media> getMedia() {
|
||||||
|
return this.media;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProposalStateCallback implements CallIntegration.Callback {
|
public class ProposalStateCallback implements CallIntegration.Callback {
|
||||||
|
@ -1126,8 +1145,11 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAudioDeviceChanged(
|
public void onAudioDeviceChanged(
|
||||||
CallIntegration.AudioDevice selectedAudioDevice,
|
final CallIntegration.AudioDevice selectedAudioDevice,
|
||||||
Set<CallIntegration.AudioDevice> availableAudioDevices) {}
|
final Set<CallIntegration.AudioDevice> availableAudioDevices) {
|
||||||
|
mXmppConnectionService.notifyJingleRtpConnectionUpdate(
|
||||||
|
selectedAudioDevice, availableAudioDevices);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCallIntegrationReject() {}
|
public void onCallIntegrationReject() {}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.crypto.axolotl.CryptoFailedException;
|
import eu.siacs.conversations.crypto.axolotl.CryptoFailedException;
|
||||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Conversational;
|
import eu.siacs.conversations.entities.Conversational;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
@ -68,7 +69,7 @@ import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class JingleRtpConnection extends AbstractJingleConnection
|
public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
implements WebRTCWrapper.EventCallback, CallIntegration.Callback {
|
implements WebRTCWrapper.EventCallback, CallIntegration.Callback, OngoingRtpSession {
|
||||||
|
|
||||||
public static final List<State> STATES_SHOWING_ONGOING_CALL =
|
public static final List<State> STATES_SHOWING_ONGOING_CALL =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
|
@ -2645,6 +2646,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
return this.sessionDuration.elapsed(TimeUnit.MILLISECONDS);
|
return this.sessionDuration.elapsed(TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CallIntegration getCallIntegration() {
|
public CallIntegration getCallIntegration() {
|
||||||
return this.callIntegration;
|
return this.callIntegration;
|
||||||
}
|
}
|
||||||
|
@ -2870,6 +2872,21 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
return remoteHasFeature(Namespace.SDP_OFFER_ANSWER);
|
return remoteHasFeature(Namespace.SDP_OFFER_ANSWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Account getAccount() {
|
||||||
|
return id.account;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Jid getWith() {
|
||||||
|
return id.with;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSessionId() {
|
||||||
|
return id.sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
private interface OnIceServersDiscovered {
|
private interface OnIceServersDiscovered {
|
||||||
void onIceServersDiscovered(List<PeerConnection.IceServer> iceServers);
|
void onIceServersDiscovered(List<PeerConnection.IceServer> iceServers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.services.CallIntegration;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public interface OngoingRtpSession {
|
public interface OngoingRtpSession {
|
||||||
Account getAccount();
|
Account getAccount();
|
||||||
|
|
||||||
Jid getWith();
|
Jid getWith();
|
||||||
|
|
||||||
String getSessionId();
|
String getSessionId();
|
||||||
|
|
||||||
|
CallIntegration getCallIntegration();
|
||||||
|
|
||||||
|
Set<Media> getMedia();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue