diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 66c4f5bcb..dac289003 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -10,7 +10,6 @@
-
@@ -33,6 +32,8 @@
+
+
> notifications = new LinkedHashMap<>();
private final HashMap mBacklogMessageCounter = new HashMap<>();
@@ -100,6 +103,14 @@ public class NotificationService {
return Pattern.compile("(?<=(^|\\s))" + Pattern.quote(nick) + "(?=\\s|$|\\p{Punct})");
}
+ private static boolean isImageMessage(Message message) {
+ return message.getType() != Message.TYPE_TEXT
+ && message.getTransferable() == null
+ && !message.isDeleted()
+ && message.getEncryption() != Message.ENCRYPTION_PGP
+ && message.getFileParams().height > 0;
+ }
+
@RequiresApi(api = Build.VERSION_CODES.O)
void initializeChannels() {
final Context c = mXmppConnectionService;
@@ -112,6 +123,7 @@ public class NotificationService {
notificationManager.createNotificationChannelGroup(new NotificationChannelGroup("status", c.getString(R.string.notification_group_status_information)));
notificationManager.createNotificationChannelGroup(new NotificationChannelGroup("chats", c.getString(R.string.notification_group_messages)));
+ notificationManager.createNotificationChannelGroup(new NotificationChannelGroup("calls", c.getString(R.string.notification_group_calls)));
final NotificationChannel foregroundServiceChannel = new NotificationChannel("foreground",
c.getString(R.string.foreground_service_channel_name),
NotificationManager.IMPORTANCE_MIN);
@@ -141,6 +153,20 @@ public class NotificationService {
exportChannel.setGroup("status");
notificationManager.createNotificationChannel(exportChannel);
+ final NotificationChannel incomingCallsChannel = new NotificationChannel("incoming_calls",
+ c.getString(R.string.incoming_calls_channel_name),
+ NotificationManager.IMPORTANCE_HIGH);
+ incomingCallsChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .build());
+ incomingCallsChannel.setShowBadge(false);
+ incomingCallsChannel.setLightColor(LED_COLOR);
+ incomingCallsChannel.enableLights(true);
+ incomingCallsChannel.setGroup("calls");
+ notificationManager.createNotificationChannel(incomingCallsChannel);
+
+
final NotificationChannel messagesChannel = new NotificationChannel("messages",
c.getString(R.string.messages_channel_name),
NotificationManager.IMPORTANCE_HIGH);
@@ -300,6 +326,53 @@ public class NotificationService {
}
}
+ public void showIncomingCallNotification(AbstractJingleConnection.Id id) {
+ final Intent fullScreenIntent = new Intent(mXmppConnectionService, RtpSessionActivity.class);
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+ 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));
+ 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.setFullScreenIntent(createPendingRtpSession(id, Intent.ACTION_VIEW, 101), true);
+ builder.setOngoing(true);
+ builder.addAction(new NotificationCompat.Action.Builder(
+ R.drawable.ic_call_end_white_48dp,
+ mXmppConnectionService.getString(R.string.dismiss_call),
+ createDismissCall(id.sessionId, 102))
+ .build());
+ builder.addAction(new NotificationCompat.Action.Builder(
+ R.drawable.ic_call_white_24dp,
+ mXmppConnectionService.getString(R.string.answer_call),
+ createPendingRtpSession(id, RtpSessionActivity.ACTION_ACCEPT, 103))
+ .build());
+ final Notification notification = builder.build();
+ notification.flags = notification.flags | Notification.FLAG_INSISTENT;
+ notify(INCOMING_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);
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
+ fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return PendingIntent.getActivity(mXmppConnectionService, requestCode, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ public void cancelIncomingCallNotification() {
+ cancel(INCOMING_CALL_NOTIFICATION_ID);
+ }
+
private void pushNow(final Message message) {
mXmppConnectionService.updateUnreadCountBadge();
if (!notify(message)) {
@@ -467,7 +540,7 @@ public class NotificationService {
private Builder buildMultipleConversation(final boolean notify, final boolean quietHours) {
final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService, quietHours ? "quiet_hours" : (notify ? "messages" : "silent_messages"));
final NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
- style.setBigContentTitle(mXmppConnectionService.getString(R.string.x_unread_conversations,notifications.size()));
+ style.setBigContentTitle(mXmppConnectionService.getString(R.string.x_unread_conversations, notifications.size()));
final StringBuilder names = new StringBuilder();
Conversation conversation = null;
for (final ArrayList messages : notifications.values()) {
@@ -652,7 +725,7 @@ public class NotificationService {
return builder.build();
}
- private void modifyForTextOnly(final Builder builder, final ArrayList messages) {
+ private void modifyForTextOnly(final Builder builder, final ArrayList messages) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
final Conversation conversation = (Conversation) messages.get(0).getConversation();
final Person.Builder meBuilder = new Person.Builder().setName(mXmppConnectionService.getString(R.string.me));
@@ -668,7 +741,7 @@ public class NotificationService {
for (Message message : messages) {
final Person sender = message.getStatus() == Message.STATUS_RECEIVED ? getPerson(message) : null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && isImageMessage(message)) {
- final Uri dataUri = FileBackend.getMediaUri(mXmppConnectionService,mXmppConnectionService.getFileBackend().getFile(message));
+ final Uri dataUri = FileBackend.getMediaUri(mXmppConnectionService, mXmppConnectionService.getFileBackend().getFile(message));
NotificationCompat.MessagingStyle.Message imageMessage = new NotificationCompat.MessagingStyle.Message(UIHelper.getMessagePreview(mXmppConnectionService, message).first, message.getTimeSent(), sender);
if (dataUri != null) {
imageMessage.setData(message.getMimeType(), dataUri);
@@ -683,7 +756,7 @@ public class NotificationService {
} else {
if (messages.get(0).getConversation().getMode() == Conversation.MODE_SINGLE) {
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getMergedBodies(messages)));
- final CharSequence preview = UIHelper.getMessagePreview(mXmppConnectionService, messages.get(messages.size()-1)).first;
+ final CharSequence preview = UIHelper.getMessagePreview(mXmppConnectionService, messages.get(messages.size() - 1)).first;
builder.setContentText(preview);
builder.setTicker(preview);
builder.setNumber(messages.size());
@@ -726,14 +799,6 @@ public class NotificationService {
return image;
}
- private static boolean isImageMessage(Message message) {
- return message.getType() != Message.TYPE_TEXT
- && message.getTransferable() == null
- && !message.isDeleted()
- && message.getEncryption() != Message.ENCRYPTION_PGP
- && message.getFileParams().height > 0;
- }
-
private Message getFirstDownloadableMessage(final Iterable messages) {
for (final Message message : messages) {
if (message.getTransferable() != null || (message.getType() == Message.TYPE_TEXT && message.treatAsDownloadable())) {
@@ -834,6 +899,14 @@ public class NotificationService {
return PendingIntent.getService(mXmppConnectionService, generateRequestCode(conversation, 16), intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
+ private PendingIntent createDismissCall(String sessionId, int requestCode) {
+ final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
+ intent.setAction(XmppConnectionService.ACTION_DISMISS_CALL);
+ intent.setPackage(mXmppConnectionService.getPackageName());
+ intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, sessionId);
+ return PendingIntent.getService(mXmppConnectionService, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
private PendingIntent createSnoozeIntent(Conversation conversation) {
final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
intent.setAction(XmppConnectionService.ACTION_SNOOZE);
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 5951b7116..1ac96354e 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -107,6 +107,7 @@ import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ChooseAccountForProfilePictureActivity;
+import eu.siacs.conversations.ui.RtpSessionActivity;
import eu.siacs.conversations.ui.SettingsActivity;
import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
@@ -165,6 +166,7 @@ public class XmppConnectionService extends Service {
public static final String ACTION_IDLE_PING = "idle_ping";
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";
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";
@@ -638,6 +640,10 @@ public class XmppConnectionService extends Service {
}
});
break;
+ 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);
+ break;
case ACTION_DISMISS_ERROR_NOTIFICATIONS:
dismissErrorNotifications();
break;
diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
index 32a0d03ef..2464f81b7 100644
--- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
@@ -25,6 +25,8 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
public static final String EXTRA_WITH = "with";
public static final String EXTRA_SESSION_ID = "session_id";
+ public static final String ACTION_ACCEPT = "accept";
+
private WeakReference rtpConnectionReference;
private ActivityRtpSessionBinding binding;
@@ -32,6 +34,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+ ;
+ Log.d(Config.LOGTAG, "RtpSessionActivity.onCreate()");
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
this.binding.rejectCall.setOnClickListener(this::rejectCall);
this.binding.endCall.setOnClickListener(this::endCall);
@@ -41,7 +49,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
@Override
public void onStart() {
super.onStart();
- Log.d(Config.LOGTAG,"RtpSessionActivity.onStart()");
+ Log.d(Config.LOGTAG, "RtpSessionActivity.onStart()");
}
private void endCall(View view) {
@@ -78,8 +86,13 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
this.rtpConnectionReference = reference;
binding.with.setText(getWith().getDisplayName());
final RtpEndUserState currentState = requireRtpConnection().getEndUserState();
+ final String action = intent.getAction();
updateStateDisplay(currentState);
updateButtonConfiguration(currentState);
+ if (ACTION_ACCEPT.equals(action)) {
+ Log.d(Config.LOGTAG,"intent action was accept");
+ requireRtpConnection().acceptCall();
+ }
}
}
@@ -137,12 +150,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
public void onJingleRtpConnectionUpdate(Account account, Jid with, RtpEndUserState state) {
final AbstractJingleConnection.Id id = requireRtpConnection().getId();
if (account == id.account && id.with.equals(with)) {
- runOnUiThread(()->{
+ runOnUiThread(() -> {
updateStateDisplay(state);
updateButtonConfiguration(state);
});
} else {
- Log.d(Config.LOGTAG,"received update for other rtp session");
+ Log.d(Config.LOGTAG, "received update for other rtp session");
}
}
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 3d346dfd5..56991635f 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
@@ -228,12 +228,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
private void startRinging() {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing");
- final Intent intent = new Intent(xmppConnectionService, RtpSessionActivity.class);
- intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- xmppConnectionService.startActivity(intent);
+ xmppConnectionService.getNotificationService().showIncomingCallNotification(id);
}
private void receiveProceed(final Jid from, final Element proceed) {
@@ -342,6 +337,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
public void rejectCall() {
Log.d(Config.LOGTAG, "todo rejecting call");
+ xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
}
public void endCall() {
@@ -359,6 +355,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
private void acceptCallFromProposed() {
transitionOrThrow(State.PROCEED);
+ xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
final MessagePacket messagePacket = new MessagePacket();
messagePacket.setTo(id.with);
//Note that Movim needs 'accept', correct is 'proceed' https://github.com/movim/movim/issues/916
@@ -368,7 +365,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
}
private void acceptCallFromSessionInitialized() {
-
+ xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
+ throw new IllegalStateException("accepting from this state has not been implemented yet");
}
private synchronized boolean isInState(State... state) {
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 3d4c35661..e7d20d98f 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -748,7 +748,9 @@
Connectivity Problems
This notification category is used to display a notification in case there is a problem connecting to an account.
Messages
+ Calls
Messages
+ Incoming calls
Silent messages
This notification group is used to display notifications that should not trigger any sound. For example when being active on another device (Grace Period).
Notification Settings
@@ -890,6 +892,8 @@
Connected
Accepting call
Ending call
+ Answer
+ Dismiss
- View %1$d Participant
- View %1$d Participants