let Conversations (not Android) play ringtone and vibration
fixes #3972 fixes #3801 fixes #3931
This commit is contained in:
parent
78c89664c4
commit
484f633180
|
@ -12,10 +12,12 @@ import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
|
import android.media.Ringtone;
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.Vibrator;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
|
@ -43,6 +45,10 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -70,12 +76,13 @@ import eu.siacs.conversations.xmpp.jingle.Media;
|
||||||
|
|
||||||
public class NotificationService {
|
public class NotificationService {
|
||||||
|
|
||||||
|
private static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
public static final Object CATCHUP_LOCK = new Object();
|
public static final Object CATCHUP_LOCK = new Object();
|
||||||
|
|
||||||
private static final int LED_COLOR = 0xff00ff00;
|
private static final int LED_COLOR = 0xff00ff00;
|
||||||
|
|
||||||
private static final int CALL_DAT = 120;
|
private static final long[] CALL_PATTERN = {0, 500, 300, 600};
|
||||||
private static final long[] CALL_PATTERN = {0, 3 * CALL_DAT, CALL_DAT, CALL_DAT, 3 * CALL_DAT, CALL_DAT, CALL_DAT};
|
|
||||||
|
|
||||||
private static final String CONVERSATIONS_GROUP = "eu.siacs.conversations";
|
private static final String CONVERSATIONS_GROUP = "eu.siacs.conversations";
|
||||||
private static final int NOTIFICATION_ID_MULTIPLIER = 1024 * 1024;
|
private static final int NOTIFICATION_ID_MULTIPLIER = 1024 * 1024;
|
||||||
|
@ -92,6 +99,10 @@ public class NotificationService {
|
||||||
private boolean mIsInForeground;
|
private boolean mIsInForeground;
|
||||||
private long mLastNotification;
|
private long mLastNotification;
|
||||||
|
|
||||||
|
private static final String INCOMING_CALLS_NOTIFICATION_CHANNEL = "incoming_calls_channel";
|
||||||
|
private Ringtone currentlyPlayingRingtone = null;
|
||||||
|
private ScheduledFuture<?> vibrationFuture;
|
||||||
|
|
||||||
NotificationService(final XmppConnectionService service) {
|
NotificationService(final XmppConnectionService service) {
|
||||||
this.mXmppConnectionService = service;
|
this.mXmppConnectionService = service;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +140,7 @@ public class NotificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager.deleteNotificationChannel("export");
|
notificationManager.deleteNotificationChannel("export");
|
||||||
|
notificationManager.deleteNotificationChannel("incoming_calls");
|
||||||
|
|
||||||
notificationManager.createNotificationChannelGroup(new NotificationChannelGroup("status", c.getString(R.string.notification_group_status_information)));
|
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("chats", c.getString(R.string.notification_group_messages)));
|
||||||
|
@ -162,20 +174,16 @@ public class NotificationService {
|
||||||
exportChannel.setGroup("status");
|
exportChannel.setGroup("status");
|
||||||
notificationManager.createNotificationChannel(exportChannel);
|
notificationManager.createNotificationChannel(exportChannel);
|
||||||
|
|
||||||
final NotificationChannel incomingCallsChannel = new NotificationChannel("incoming_calls",
|
final NotificationChannel incomingCallsChannel = new NotificationChannel(INCOMING_CALLS_NOTIFICATION_CHANNEL,
|
||||||
c.getString(R.string.incoming_calls_channel_name),
|
c.getString(R.string.incoming_calls_channel_name),
|
||||||
NotificationManager.IMPORTANCE_HIGH);
|
NotificationManager.IMPORTANCE_HIGH);
|
||||||
incomingCallsChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), new AudioAttributes.Builder()
|
incomingCallsChannel.setSound(null, null);
|
||||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
|
||||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
|
|
||||||
.build());
|
|
||||||
incomingCallsChannel.setShowBadge(false);
|
incomingCallsChannel.setShowBadge(false);
|
||||||
incomingCallsChannel.setLightColor(LED_COLOR);
|
incomingCallsChannel.setLightColor(LED_COLOR);
|
||||||
incomingCallsChannel.enableLights(true);
|
incomingCallsChannel.enableLights(true);
|
||||||
incomingCallsChannel.setGroup("calls");
|
incomingCallsChannel.setGroup("calls");
|
||||||
incomingCallsChannel.setBypassDnd(true);
|
incomingCallsChannel.setBypassDnd(true);
|
||||||
incomingCallsChannel.enableVibration(true);
|
incomingCallsChannel.enableVibration(false);
|
||||||
incomingCallsChannel.setVibrationPattern(CALL_PATTERN);
|
|
||||||
notificationManager.createNotificationChannel(incomingCallsChannel);
|
notificationManager.createNotificationChannel(incomingCallsChannel);
|
||||||
|
|
||||||
final NotificationChannel ongoingCallsChannel = new NotificationChannel("ongoing_calls",
|
final NotificationChannel ongoingCallsChannel = new NotificationChannel("ongoing_calls",
|
||||||
|
@ -387,14 +395,32 @@ public class NotificationService {
|
||||||
notify(DELIVERY_FAILED_NOTIFICATION_ID, summaryNotification);
|
notify(DELIVERY_FAILED_NOTIFICATION_ID, summaryNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showIncomingCallNotification(final AbstractJingleConnection.Id id, final Set<Media> media) {
|
public void startRinging(final AbstractJingleConnection.Id id, final Set<Media> media) {
|
||||||
|
showIncomingCallNotification(id, media);
|
||||||
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
|
||||||
|
final Resources resources = mXmppConnectionService.getResources();
|
||||||
|
final Uri uri = Uri.parse(preferences.getString("call_ringtone", resources.getString(R.string.incoming_call_ringtone)));
|
||||||
|
this.currentlyPlayingRingtone = RingtoneManager.getRingtone(mXmppConnectionService, uri);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
this.currentlyPlayingRingtone.setLooping(true);
|
||||||
|
}
|
||||||
|
this.currentlyPlayingRingtone.play();
|
||||||
|
this.vibrationFuture = SCHEDULED_EXECUTOR_SERVICE.scheduleAtFixedRate(
|
||||||
|
new VibrationRunnable(),
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showIncomingCallNotification(final AbstractJingleConnection.Id id, final Set<Media> media) {
|
||||||
final Intent fullScreenIntent = new Intent(mXmppConnectionService, RtpSessionActivity.class);
|
final Intent fullScreenIntent = new Intent(mXmppConnectionService, RtpSessionActivity.class);
|
||||||
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
|
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
|
||||||
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
|
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
|
||||||
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
|
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
|
||||||
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mXmppConnectionService, "incoming_calls");
|
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mXmppConnectionService, INCOMING_CALLS_NOTIFICATION_CHANNEL);
|
||||||
if (media.contains(Media.VIDEO)) {
|
if (media.contains(Media.VIDEO)) {
|
||||||
builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
|
builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
|
||||||
builder.setContentTitle(mXmppConnectionService.getString(R.string.rtp_state_incoming_video_call));
|
builder.setContentTitle(mXmppConnectionService.getString(R.string.rtp_state_incoming_video_call));
|
||||||
|
@ -468,9 +494,23 @@ public class NotificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelIncomingCallNotification() {
|
public void cancelIncomingCallNotification() {
|
||||||
|
stopSoundAndVibration();
|
||||||
cancel(INCOMING_CALL_NOTIFICATION_ID);
|
cancel(INCOMING_CALL_NOTIFICATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stopSoundAndVibration() {
|
||||||
|
if (this.currentlyPlayingRingtone != null) {
|
||||||
|
if (this.currentlyPlayingRingtone.isPlaying()) {
|
||||||
|
Log.d(Config.LOGTAG, "stop playing ring tone");
|
||||||
|
}
|
||||||
|
this.currentlyPlayingRingtone.stop();
|
||||||
|
}
|
||||||
|
if (this.vibrationFuture != null && !this.vibrationFuture.isCancelled()) {
|
||||||
|
Log.d(Config.LOGTAG, "cancel vibration");
|
||||||
|
this.vibrationFuture.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void cancelIncomingCallNotification(final Context context) {
|
public static void cancelIncomingCallNotification(final Context context) {
|
||||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||||
try {
|
try {
|
||||||
|
@ -636,17 +676,7 @@ public class NotificationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modifyIncomingCall(Builder mBuilder) {
|
private void modifyIncomingCall(final Builder mBuilder) {
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
|
|
||||||
final Resources resources = mXmppConnectionService.getResources();
|
|
||||||
final String ringtone = preferences.getString("call_ringtone", resources.getString(R.string.incoming_call_ringtone));
|
|
||||||
mBuilder.setVibrate(CALL_PATTERN);
|
|
||||||
final Uri uri = Uri.parse(ringtone);
|
|
||||||
try {
|
|
||||||
mBuilder.setSound(fixRingtoneUri(uri));
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
Log.d(Config.LOGTAG, "unable to use custom notification sound " + uri.toString());
|
|
||||||
}
|
|
||||||
mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||||
setNotificationColor(mBuilder);
|
setNotificationColor(mBuilder);
|
||||||
mBuilder.setLights(LED_COLOR, 2000, 3000);
|
mBuilder.setLights(LED_COLOR, 2000, 3000);
|
||||||
|
@ -1253,4 +1283,13 @@ public class NotificationService {
|
||||||
Log.d(Config.LOGTAG, "unable to cancel notification", e);
|
Log.d(Config.LOGTAG, "unable to cancel notification", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class VibrationRunnable implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Vibrator vibrator = (Vibrator) mXmppConnectionService.getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
vibrator.vibrate(CALL_PATTERN, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.os.PowerManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Rational;
|
import android.util.Rational;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -146,6 +147,16 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
|
||||||
|
if (xmppConnectionService != null) {
|
||||||
|
xmppConnectionService.getNotificationService().stopSoundAndVibration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isHelpButtonVisible() {
|
private boolean isHelpButtonVisible() {
|
||||||
try {
|
try {
|
||||||
return STATES_SHOWING_HELP_BUTTON.contains(requireRtpConnection().getEndUserState());
|
return STATES_SHOWING_HELP_BUTTON.contains(requireRtpConnection().getEndUserState());
|
||||||
|
|
|
@ -16,6 +16,7 @@ import androidx.annotation.BoolRes;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
@ -31,12 +32,10 @@ public class Compatibility {
|
||||||
"led",
|
"led",
|
||||||
"notification_ringtone",
|
"notification_ringtone",
|
||||||
"notification_headsup",
|
"notification_headsup",
|
||||||
"vibrate_on_notification",
|
"vibrate_on_notification"
|
||||||
"call_ringtone"
|
|
||||||
);
|
);
|
||||||
private static final List<String> UNUESD_SETTINGS_PRE_TWENTYSIX = Arrays.asList(
|
private static final List<String> UNUESD_SETTINGS_PRE_TWENTYSIX = Collections.singletonList(
|
||||||
"message_notification_settings",
|
"message_notification_settings"
|
||||||
"call_notification_settings"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -597,7 +597,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
private void startRinging() {
|
private void startRinging() {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing");
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing");
|
||||||
ringingTimeoutFuture = jingleConnectionManager.schedule(this::ringingTimeout, BUSY_TIME_OUT, TimeUnit.SECONDS);
|
ringingTimeoutFuture = jingleConnectionManager.schedule(this::ringingTimeout, BUSY_TIME_OUT, TimeUnit.SECONDS);
|
||||||
xmppConnectionService.getNotificationService().showIncomingCallNotification(id, getMedia());
|
xmppConnectionService.getNotificationService().startRinging(id, getMedia());
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void ringingTimeout() {
|
private synchronized void ringingTimeout() {
|
||||||
|
|
|
@ -113,19 +113,6 @@
|
||||||
android:value="messages" />
|
android:value="messages" />
|
||||||
</intent>
|
</intent>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
<PreferenceScreen
|
|
||||||
android:key="call_notification_settings"
|
|
||||||
android:summary="@string/pref_more_notification_settings_summary"
|
|
||||||
android:title="@string/pref_incoming_call_notification_settings">
|
|
||||||
<intent android:action="android.settings.CHANNEL_NOTIFICATION_SETTINGS">
|
|
||||||
<extra
|
|
||||||
android:name="android.provider.extra.APP_PACKAGE"
|
|
||||||
android:value="@string/applicationId" />
|
|
||||||
<extra
|
|
||||||
android:name="android.provider.extra.CHANNEL_ID"
|
|
||||||
android:value="incoming_calls" />
|
|
||||||
</intent>
|
|
||||||
</PreferenceScreen>
|
|
||||||
<RingtonePreference
|
<RingtonePreference
|
||||||
android:defaultValue="@string/notification_ringtone"
|
android:defaultValue="@string/notification_ringtone"
|
||||||
android:key="notification_ringtone"
|
android:key="notification_ringtone"
|
||||||
|
|
Loading…
Reference in New Issue