Detailed changes
@@ -76,6 +76,7 @@ public class NotificationService {
private static final int NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 2;
private static final int ERROR_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 6;
private static final int INCOMING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 8;
+ private static final int ONGOING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 10;
private final XmppConnectionService mXmppConnectionService;
private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>();
private final HashMap<Conversation, AtomicInteger> mBacklogMessageCounter = new HashMap<>();
@@ -166,6 +167,13 @@ public class NotificationService {
incomingCallsChannel.setGroup("calls");
notificationManager.createNotificationChannel(incomingCallsChannel);
+ final NotificationChannel ongoingCallsChannel = new NotificationChannel("ongoing_calls",
+ c.getString(R.string.ongoing_calls_channel_name),
+ NotificationManager.IMPORTANCE_LOW);
+ ongoingCallsChannel.setShowBadge(false);
+ ongoingCallsChannel.setGroup("calls");
+ notificationManager.createNotificationChannel(ongoingCallsChannel);
+
final NotificationChannel messagesChannel = new NotificationChannel("messages",
c.getString(R.string.messages_channel_name),
@@ -333,7 +341,6 @@ public class NotificationService {
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- final PendingIntent pendingIntent = PendingIntent.getActivity(mXmppConnectionService, 101, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mXmppConnectionService, "incoming_calls");
builder.setSmallIcon(R.drawable.ic_call_white_24dp);
builder.setContentTitle(mXmppConnectionService.getString(R.string.rtp_state_incoming_call));
@@ -346,7 +353,7 @@ public class NotificationService {
builder.addAction(new NotificationCompat.Action.Builder(
R.drawable.ic_call_end_white_48dp,
mXmppConnectionService.getString(R.string.dismiss_call),
- createDismissCall(id.sessionId, 102))
+ createCallAction(id.sessionId, XmppConnectionService.ACTION_DISMISS_CALL, 102))
.build());
builder.addAction(new NotificationCompat.Action.Builder(
R.drawable.ic_call_white_24dp,
@@ -358,6 +365,26 @@ public class NotificationService {
notify(INCOMING_CALL_NOTIFICATION_ID, builder.build());
}
+ public void showOngoingCallNotification(final AbstractJingleConnection.Id id) {
+ 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));
+ builder.setContentText(id.account.getRoster().getContact(id.with).getDisplayName());
+ builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+ builder.setPriority(NotificationCompat.PRIORITY_HIGH);
+ builder.setCategory(NotificationCompat.CATEGORY_CALL);
+ builder.setContentIntent(createPendingRtpSession(id, Intent.ACTION_VIEW, 101));
+ builder.setOngoing(true);
+ builder.addAction(new NotificationCompat.Action.Builder(
+ R.drawable.ic_call_end_white_48dp,
+ mXmppConnectionService.getString(R.string.hang_up),
+ createCallAction(id.sessionId, XmppConnectionService.ACTION_END_CALL, 104))
+ .build());
+ final Notification notification = builder.build();
+ notification.flags = notification.flags | Notification.FLAG_INSISTENT;
+ notify(ONGOING_CALL_NOTIFICATION_ID, builder.build());
+ }
+
private PendingIntent createPendingRtpSession(final AbstractJingleConnection.Id id, final String action, final int requestCode) {
final Intent fullScreenIntent = new Intent(mXmppConnectionService, RtpSessionActivity.class);
fullScreenIntent.setAction(action);
@@ -373,6 +400,10 @@ public class NotificationService {
cancel(INCOMING_CALL_NOTIFICATION_ID);
}
+ public void cancelOngoingCallNotification() {
+ cancel(ONGOING_CALL_NOTIFICATION_ID);
+ }
+
private void pushNow(final Message message) {
mXmppConnectionService.updateUnreadCountBadge();
if (!notify(message)) {
@@ -899,9 +930,9 @@ public class NotificationService {
return PendingIntent.getService(mXmppConnectionService, generateRequestCode(conversation, 16), intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
- private PendingIntent createDismissCall(String sessionId, int requestCode) {
+ private PendingIntent createCallAction(String sessionId, final String action, int requestCode) {
final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
- intent.setAction(XmppConnectionService.ACTION_DISMISS_CALL);
+ intent.setAction(action);
intent.setPackage(mXmppConnectionService.getPackageName());
intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, sessionId);
return PendingIntent.getService(mXmppConnectionService, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
@@ -167,6 +167,7 @@ public class XmppConnectionService extends Service {
public static final String ACTION_FCM_TOKEN_REFRESH = "fcm_token_refresh";
public static final String ACTION_FCM_MESSAGE_RECEIVED = "fcm_message_received";
public static final String ACTION_DISMISS_CALL = "dismiss_call";
+ public static final String ACTION_END_CALL = "end_call";
private static final String ACTION_POST_CONNECTIVITY_CHANGE = "eu.siacs.conversations.POST_CONNECTIVITY_CHANGE";
private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp";
@@ -640,10 +641,17 @@ public class XmppConnectionService extends Service {
}
});
break;
- case ACTION_DISMISS_CALL:
+ case ACTION_DISMISS_CALL: {
final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
- Log.d(Config.LOGTAG,"received intent to dismiss call with session id "+sessionId);
+ Log.d(Config.LOGTAG, "received intent to dismiss call with session id " + sessionId);
mJingleConnectionManager.rejectRtpSession(sessionId);
+ }
+ break;
+ case ACTION_END_CALL: {
+ final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
+ Log.d(Config.LOGTAG, "received intent to end call with session id " + sessionId);
+ mJingleConnectionManager.endRtpSession(sessionId);
+ }
break;
case ACTION_DISMISS_ERROR_NOTIFICATIONS:
dismissErrorNotifications();
@@ -3978,7 +3986,7 @@ public class XmppConnectionService extends Service {
}
public void notifyJingleRtpConnectionUpdate(final Account account, final Jid with, final String sessionId, final RtpEndUserState state) {
- for(OnJingleRtpConnectionUpdate listener : threadSafeList(this.onJingleRtpConnectionUpdate)) {
+ for (OnJingleRtpConnectionUpdate listener : threadSafeList(this.onJingleRtpConnectionUpdate)) {
listener.onJingleRtpConnectionUpdate(account, with, sessionId, state);
}
}
@@ -237,6 +237,9 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
finish();
return;
}
+ if (JingleRtpConnection.STATES_SHOWING_ONGOING_CALL.contains(requireRtpConnection().getState())) {
+ putScreenInCallMode();
+ }
binding.with.setText(getWith().getDisplayName());
updateStateDisplay(currentState);
updateButtonConfiguration(currentState);
@@ -1,21 +1,19 @@
package eu.siacs.conversations.xmpp.jingle;
+import android.util.Base64;
import android.util.Log;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import java.lang.ref.WeakReference;
+import java.security.SecureRandom;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.services.AbstractConnectionManager;
@@ -271,7 +269,9 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
static String nextRandomId() {
- return UUID.randomUUID().toString();
+ final byte[] id = new byte[16];
+ new SecureRandom().nextBytes(id);
+ return Base64.encodeToString(id, Base64.NO_WRAP | Base64.NO_PADDING);
}
public void deliverIbbPacket(Account account, IqPacket packet) {
@@ -354,6 +354,16 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
}
+ public void endRtpSession(final String sessionId) {
+ for (final AbstractJingleConnection connection : this.connections.values()) {
+ if (connection.getId().sessionId.equals(sessionId)) {
+ if (connection instanceof JingleRtpConnection) {
+ ((JingleRtpConnection) connection).endCall();
+ }
+ }
+ }
+ }
+
public void failProceed(Account account, final Jid with, String sessionId) {
final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, with, sessionId);
final AbstractJingleConnection existingJingleConnection = connections.get(id);
@@ -374,7 +384,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
public static RtpSessionProposal of(Account account, Jid with) {
- return new RtpSessionProposal(account, with, UUID.randomUUID().toString());
+ return new RtpSessionProposal(account, with, nextRandomId());
}
@Override
@@ -74,6 +74,13 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
VALID_TRANSITIONS = transitionBuilder.build();
}
+ public static final List<State> STATES_SHOWING_ONGOING_CALL = Arrays.asList(
+ State.PROCEED,
+ State.SESSION_INITIALIZED,
+ State.SESSION_INITIALIZED_PRE_APPROVED,
+ State.SESSION_ACCEPTED
+ );
+
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
private final ArrayDeque<IceCandidate> pendingIceCandidates = new ArrayDeque<>();
private State state = State.NULL;
@@ -727,6 +734,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
this.state = target;
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": transitioned into " + target);
updateEndUserState();
+ updateOngoingCallNotification();
return true;
} else {
return false;
@@ -759,6 +767,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
xmppConnectionService.notifyJingleRtpConnectionUpdate(id.account, id.with, id.sessionId, getEndUserState());
}
+ private void updateOngoingCallNotification() {
+ if (STATES_SHOWING_ONGOING_CALL.contains(this.state)) {
+ xmppConnectionService.getNotificationService().showOngoingCallNotification(id);
+ } else {
+ xmppConnectionService.getNotificationService().cancelOngoingCallNotification();
+ }
+ }
+
private void discoverIceServers(final OnIceServersDiscovered onIceServersDiscovered) {
if (id.account.getXmppConnection().getFeatures().extendedServiceDiscovery()) {
final IqPacket request = new IqPacket(IqPacket.TYPE.GET);
@@ -815,6 +831,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
}
}
+ public State getState() {
+ return this.state;
+ }
+
private interface OnIceServersDiscovered {
void onIceServersDiscovered(List<PeerConnection.IceServer> iceServers);
}
@@ -751,6 +751,7 @@
<string name="notification_group_calls">Calls</string>
<string name="messages_channel_name">Messages</string>
<string name="incoming_calls_channel_name">Incoming calls</string>
+ <string name="ongoing_calls_channel_name">Ongoing calls</string>
<string name="silent_messages_channel_name">Silent messages</string>
<string name="silent_messages_channel_description">This notification group is used to display notifications that should not trigger any sound. For example when being active on another device (Grace Period).</string>
<string name="pref_more_notification_settings">Notification Settings</string>
@@ -899,6 +900,8 @@
<string name="rtp_state_declined_or_busy">Busy</string>
<string name="rtp_state_connectivity_error">Unable to connect call</string>
<string name="rtp_state_application_failure">Application failure</string>
+ <string name="hang_up">Hang up</string>
+ <string name="ongoing_call">Ongoing call</string>
<plurals name="view_users">
<item quantity="one">View %1$d Participant</item>
<item quantity="other">View %1$d Participants</item>