From 36e117979a0e890c5be0f29c560252d610f11d18 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 15 Apr 2020 22:40:37 +0200 Subject: [PATCH] put 'video' in ongoing video call notification --- .../services/NotificationService.java | 11 ++-- .../services/XmppConnectionService.java | 42 +++++++++++---- .../conversations/ui/RtpSessionActivity.java | 51 +++++++++++++------ .../xmpp/jingle/JingleRtpConnection.java | 27 ++++++---- src/main/res/values/strings.xml | 1 + 5 files changed, 93 insertions(+), 39 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index cbd11f1d7..b6257cf92 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -372,10 +372,15 @@ public class NotificationService { notify(INCOMING_CALL_NOTIFICATION_ID, notification); } - public Notification getOngoingCallNotification(final AbstractJingleConnection.Id id) { + public Notification getOngoingCallNotification(final AbstractJingleConnection.Id id, final Set media) { final NotificationCompat.Builder builder = new NotificationCompat.Builder(mXmppConnectionService, "ongoing_calls"); - builder.setSmallIcon(R.drawable.ic_call_white_24dp); - builder.setContentTitle(mXmppConnectionService.getString(R.string.ongoing_call)); + if (media.contains(Media.VIDEO)) { + builder.setSmallIcon(R.drawable.ic_videocam_white_24dp); + builder.setContentTitle(mXmppConnectionService.getString(R.string.ongoing_video_call)); + } else { + builder.setSmallIcon(R.drawable.ic_call_white_24dp); + builder.setContentTitle(mXmppConnectionService.getString(R.string.ongoing_call)); + } builder.setContentText(id.account.getRoster().getContact(id.with).getDisplayName()); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); builder.setPriority(NotificationCompat.PRIORITY_HIGH); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index d7adc05e9..0efa27618 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -42,6 +42,7 @@ import android.util.Log; import android.util.LruCache; import android.util.Pair; +import com.google.common.base.Objects; import com.google.common.base.Strings; import org.conscrypt.Conscrypt; @@ -145,6 +146,7 @@ import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; +import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.RtpEndUserState; import eu.siacs.conversations.xmpp.mam.MamReference; import eu.siacs.conversations.xmpp.pep.Avatar; @@ -209,7 +211,7 @@ public class XmppConnectionService extends Service { private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false); private AtomicBoolean mForceForegroundService = new AtomicBoolean(false); private AtomicBoolean mForceDuringOnCreate = new AtomicBoolean(false); - private AtomicReference ongoingCall = new AtomicReference<>(); + private AtomicReference ongoingCall = new AtomicReference<>(); private OnMessagePacketReceived mMessageParser = new MessageParser(this); private OnPresencePacketReceived mPresenceParser = new PresenceParser(this); private IqParser mIqParser = new IqParser(this); @@ -1228,24 +1230,23 @@ public class XmppConnectionService extends Service { toggleForegroundService(false); } - public void setOngoingCall(AbstractJingleConnection.Id id) { - ongoingCall.set(id); + public void setOngoingCall(AbstractJingleConnection.Id id, Set media) { + ongoingCall.set(new OngoingCall(id, media)); toggleForegroundService(false); } - public void removeOngoingCall(AbstractJingleConnection.Id id) { - if (ongoingCall.compareAndSet(id, null)) { - toggleForegroundService(false); - } + public void removeOngoingCall() { + ongoingCall.set(null); + toggleForegroundService(false); } private void toggleForegroundService(boolean force) { final boolean status; - final AbstractJingleConnection.Id ongoing = ongoingCall.get(); + final OngoingCall ongoing = ongoingCall.get(); if (force || mForceDuringOnCreate.get() || mForceForegroundService.get() || ongoing != null || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) { final Notification notification; if (ongoing != null) { - notification = this.mNotificationService.getOngoingCallNotification(ongoing); + notification = this.mNotificationService.getOngoingCallNotification(ongoing.id, ongoing.media); startForeground(NotificationService.ONGOING_CALL_NOTIFICATION_ID, notification); mNotificationService.cancel(NotificationService.FOREGROUND_NOTIFICATION_ID); } else { @@ -4753,4 +4754,27 @@ public class XmppConnectionService extends Service { onStartCommand(intent, 0, 0); } } + + public static class OngoingCall { + private final AbstractJingleConnection.Id id; + private final Set media; + + public OngoingCall(AbstractJingleConnection.Id id, Set media) { + this.id = id; + this.media = media; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OngoingCall that = (OngoingCall) o; + return Objects.equal(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + } } diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index a920dfa51..be8c21862 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -47,6 +47,12 @@ import static java.util.Arrays.asList; public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate { + private static final List END_CARD = Arrays.asList( + RtpEndUserState.APPLICATION_ERROR, + RtpEndUserState.DECLINED_OR_BUSY, + RtpEndUserState.CONNECTIVITY_ERROR + ); + private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session"; private static final int REQUEST_ACCEPT_CALL = 0x1111; @@ -116,23 +122,27 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe permissions = ImmutableList.of(Manifest.permission.RECORD_AUDIO); } if (PermissionUtils.hasPermission(this, permissions, REQUEST_ACCEPT_CALL)) { - //TODO like wise the propose; we might just wait here for the audio manager to come up putScreenInCallMode(); requireRtpConnection().acceptCall(); } } - @SuppressLint("WakelockTimeout") private void putScreenInCallMode() { - //TODO for video calls we actually do want to keep the screen on - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - final JingleRtpConnection rtpConnection = rtpConnectionReference != null ? rtpConnectionReference.get() : null; - final AppRTCAudioManager audioManager = rtpConnection == null ? null : rtpConnection.getAudioManager(); - if (audioManager == null || audioManager.getSelectedAudioDevice() == AppRTCAudioManager.AudioDevice.EARPIECE) { - acquireProximityWakeLock(); + putScreenInCallMode(requireRtpConnection().getMedia()); + } + + private void putScreenInCallMode(final Set media) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + if (!media.contains(Media.VIDEO)) { + final JingleRtpConnection rtpConnection = rtpConnectionReference != null ? rtpConnectionReference.get() : null; + final AppRTCAudioManager audioManager = rtpConnection == null ? null : rtpConnection.getAudioManager(); + if (audioManager == null || audioManager.getSelectedAudioDevice() == AppRTCAudioManager.AudioDevice.EARPIECE) { + acquireProximityWakeLock(); + } } } + @SuppressLint("WakelockTimeout") private void acquireProximityWakeLock() { final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (powerManager == null) { @@ -234,8 +244,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe private void proposeJingleRtpSession(final Account account, final Jid with, final Set media) { xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with, media); - //TODO maybe we don’t want to acquire a wake lock just yet and wait for audio manager to discover what speaker we are using - putScreenInCallMode(); + putScreenInCallMode(media); } @Override @@ -570,10 +579,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe @Override public void onJingleRtpConnectionUpdate(Account account, Jid with, final String sessionId, RtpEndUserState state) { - if (Arrays.asList(RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.DECLINED_OR_BUSY).contains(state)) { - releaseProximityWakeLock(); - } Log.d(Config.LOGTAG, "onJingleRtpConnectionUpdate(" + state + ")"); + if (END_CARD.contains(state)) { + Log.d(Config.LOGTAG,"end card reached"); + releaseProximityWakeLock(); + runOnUiThread(()-> getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); + } if (with.isBareJid()) { updateRtpSessionProposalState(account, with, state); return; @@ -588,7 +599,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe if (state == RtpEndUserState.ENDED) { finish(); return; - } else if (asList(RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONNECTIVITY_ERROR).contains(state)) { + } else if (END_CARD.contains(state)) { //todo remember if we were video resetIntent(account, with, state); } @@ -608,14 +619,22 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set availableAudioDevices) { Log.d(Config.LOGTAG, "onAudioDeviceChanged in activity: selected:" + selectedAudioDevice + ", available:" + availableAudioDevices); try { - if (requireRtpConnection().getEndUserState() == RtpEndUserState.CONNECTED && !getMedia().contains(Media.VIDEO)) { + if (getMedia().contains(Media.VIDEO)) { + Log.d(Config.LOGTAG,"nothing to do; in video mode"); + return; + } + final RtpEndUserState endUserState = requireRtpConnection().getEndUserState(); + if (endUserState == RtpEndUserState.CONNECTED) { final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager(); updateInCallButtonConfigurationSpeaker( audioManager.getSelectedAudioDevice(), audioManager.getAudioDevices().size() ); + } else if (END_CARD.contains(endUserState)) { + Log.d(Config.LOGTAG,"onAudioDeviceChanged() nothing to do because end card has been reached"); + } else { + putProximityWakeLockInProperState(); } - putProximityWakeLockInProperState(); } catch (IllegalStateException e) { Log.d(Config.LOGTAG, "RTP connection was not available when audio device changed"); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 976e3ad3e..5e2446788 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -289,9 +289,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } else { target = State.SESSION_INITIALIZED; } - if (transition(target)) { + if (transition(target, () -> this.initiatorRtpContentMap = contentMap)) { respondOk(jinglePacket); - this.initiatorRtpContentMap = contentMap; if (target == State.SESSION_INITIALIZED_PRE_APPROVED) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": automatically accepting session-initiate"); sendSessionAccept(); @@ -323,6 +322,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web sendSessionTerminate(Reason.FAILED_APPLICATION, e.getMessage()); return; } + //TODO check that session accept content media matched ours Log.d(Config.LOGTAG, "processing session-accept with " + contentMap.contents.size() + " contents"); if (transition(State.SESSION_ACCEPTED)) { respondOk(jinglePacket); @@ -500,7 +500,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web final boolean originatedFromMyself = from.asBareJid().equals(id.account.getJid().asBareJid()); if (originatedFromMyself) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": saw proposal from mysql. ignoring"); - } else if (isInState(State.NULL)) { + } else if (transition(State.PROPOSED, () -> { final Collection descriptions = Collections2.transform( Collections2.filter(propose.getDescriptions(), d -> d instanceof RtpDescription), input -> (RtpDescription) input @@ -509,7 +509,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web Preconditions.checkState(!media.contains(Media.UNKNOWN), "RTP descriptions contain unknown media"); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received session proposal from " + from + " for " + media); this.proposedMedia = Sets.newHashSet(media); - transitionOrThrow(State.PROPOSED); + })) { if (serverMsgId != null) { this.message.setServerMsgId(serverMsgId); } @@ -720,10 +720,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web return RtpEndUserState.CONNECTING; } else if (state == PeerConnection.PeerConnectionState.CLOSED) { return RtpEndUserState.ENDING_CALL; - } else if (state == PeerConnection.PeerConnectionState.FAILED) { - return RtpEndUserState.CONNECTIVITY_ERROR; } else { - return RtpEndUserState.ENDING_CALL; + return RtpEndUserState.CONNECTIVITY_ERROR; } case REJECTED: case TERMINATED_DECLINED_OR_BUSY: @@ -876,10 +874,17 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web return Arrays.asList(state).contains(this.state); } - private synchronized boolean transition(final State target) { + private boolean transition(final State target) { + return transition(target, null); + } + + private synchronized boolean transition(final State target, final Runnable runnable) { final Collection validTransitions = VALID_TRANSITIONS.get(this.state); if (validTransitions != null && validTransitions.contains(target)) { this.state = target; + if (runnable != null) { + runnable.run(); + } Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": transitioned into " + target); updateEndUserState(); updateOngoingCallNotification(); @@ -909,7 +914,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (newState == PeerConnection.PeerConnectionState.CONNECTED && this.rtpConnectionStarted == 0) { this.rtpConnectionStarted = SystemClock.elapsedRealtime(); } - if (newState == PeerConnection.PeerConnectionState.FAILED) { + if (Arrays.asList(PeerConnection.PeerConnectionState.FAILED, PeerConnection.PeerConnectionState.DISCONNECTED).contains(newState)) { if (TERMINATED.contains(this.state)) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not sending session-terminate after connectivity error because session is already in state " + this.state); return; @@ -949,9 +954,9 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web private void updateOngoingCallNotification() { if (STATES_SHOWING_ONGOING_CALL.contains(this.state)) { - xmppConnectionService.setOngoingCall(id); + xmppConnectionService.setOngoingCall(id, getMedia()); } else { - xmppConnectionService.removeOngoingCall(id); + xmppConnectionService.removeOngoingCall(); } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bcb757cac..6cdab665b 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -903,6 +903,7 @@ Application failure Hang up Ongoing call + Ongoing video call Disable Tor to make calls Incoming call Incoming call · %s