Commit bc59f475 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩
Browse files

Handle vibration for incoming call for Android in CoreService

parent 2792e073
...@@ -10,7 +10,10 @@ This changelog file was started on October 2019. Previous changes were more or l ...@@ -10,7 +10,10 @@ This changelog file was started on October 2019. Previous changes were more or l
## [Unreleased] ## [Unreleased]
## [4.5.2] 2021-04-14
### Added
- CoreService class for Android can make the device vibrate while incoming call is ringing.
## [4.5.0] 2021-03-29 ## [4.5.0] 2021-03-29
......
...@@ -2763,6 +2763,15 @@ bool_t linphone_core_is_auto_iterate_enabled(LinphoneCore *core) { ...@@ -2763,6 +2763,15 @@ bool_t linphone_core_is_auto_iterate_enabled(LinphoneCore *core) {
return core->auto_iterate_enabled; return core->auto_iterate_enabled;
} }
void linphone_core_set_vibration_on_incoming_call_enabled(LinphoneCore *core, bool_t enable) {
linphone_config_set_int(core->config, "misc", "vibrate_on_incoming_call", enable);
core->vibrate_on_incoming_call = enable;
}
bool_t linphone_core_is_vibration_on_incoming_call_enabled(LinphoneCore *core) {
return core->vibrate_on_incoming_call;
}
static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata, void *system_context, bool_t automatically_start) { static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata, void *system_context, bool_t automatically_start) {
LinphoneFactory *lfactory = linphone_factory_get(); LinphoneFactory *lfactory = linphone_factory_get();
LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new(); LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new();
...@@ -2790,12 +2799,14 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig ...@@ -2790,12 +2799,14 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
bool_t push_notification_default = FALSE; bool_t push_notification_default = FALSE;
bool_t auto_iterate_default = FALSE; bool_t auto_iterate_default = FALSE;
bool_t vibration_incoming_call_default = FALSE;
#if __ANDROID__ || TARGET_OS_IPHONE #if __ANDROID__ || TARGET_OS_IPHONE
push_notification_default = TRUE; push_notification_default = TRUE;
auto_iterate_default = TRUE; auto_iterate_default = TRUE;
#endif #endif
lc->push_notification_enabled = !!linphone_config_get_int(lc->config, "net", "push_notification", push_notification_default); lc->push_notification_enabled = !!linphone_config_get_int(lc->config, "net", "push_notification", push_notification_default);
lc->auto_iterate_enabled = !!linphone_config_get_int(lc->config, "misc", "auto_iterate", auto_iterate_default); lc->auto_iterate_enabled = !!linphone_config_get_int(lc->config, "misc", "auto_iterate", auto_iterate_default);
lc->vibrate_on_incoming_call = !!linphone_config_get_int(lc->config, "misc", "vibrate_on_incoming_call", vibration_incoming_call_default);
#ifdef __ANDROID__ #ifdef __ANDROID__
if (system_context) { if (system_context) {
......
...@@ -866,6 +866,9 @@ namespace LinphonePrivate { ...@@ -866,6 +866,9 @@ namespace LinphonePrivate {
char * push_notification_param; \ char * push_notification_param; \
char * push_notification_prid; \ char * push_notification_prid; \
bool_t auto_iterate_enabled; \ bool_t auto_iterate_enabled; \
bool_t native_ringing_enabled; bool_t native_ringing_enabled; \
bool_t vibrate_on_incoming_call; \
#endif /* _PRIVATE_STRUCTS_H_ */ #endif /* _PRIVATE_STRUCTS_H_ */
...@@ -5352,6 +5352,22 @@ LINPHONE_PUBLIC void linphone_core_set_auto_iterate_enabled(LinphoneCore *core, ...@@ -5352,6 +5352,22 @@ LINPHONE_PUBLIC void linphone_core_set_auto_iterate_enabled(LinphoneCore *core,
*/ */
LINPHONE_PUBLIC bool_t linphone_core_is_auto_iterate_enabled(LinphoneCore *core); LINPHONE_PUBLIC bool_t linphone_core_is_auto_iterate_enabled(LinphoneCore *core);
/**
* Enable vibration will incoming call is ringing (Android only).
* @param core The #LinphoneCore @notnil
* @return TRUE if the device should vibrate while an incoming call is ringing, FALSE otherwise
* @ingroup misc
*/
LINPHONE_PUBLIC void linphone_core_set_vibration_on_incoming_call_enabled(LinphoneCore *core, bool_t enable);
/**
* Gets whether the device will vibrate while an incoming call is ringing (Android only).
* @param core The #LinphoneCore @notnil
* @return TRUE if the device will vibrate (if possible), FALSE otherwise
* @ingroup misc
*/
LINPHONE_PUBLIC bool_t linphone_core_is_vibration_on_incoming_call_enabled(LinphoneCore *core);
/** /**
* Returns a list of audio devices, with only the first device for each type * Returns a list of audio devices, with only the first device for each type
* To have the list of all audio devices, use #linphone_core_get_extended_audio_devices() * To have the list of all audio devices, use #linphone_core_get_extended_audio_devices()
......
...@@ -21,6 +21,7 @@ package org.linphone.core.tools.compatibility; ...@@ -21,6 +21,7 @@ package org.linphone.core.tools.compatibility;
import android.content.Context; import android.content.Context;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.os.Vibrator;
import org.linphone.mediastream.Version; import org.linphone.mediastream.Version;
...@@ -65,4 +66,12 @@ public class DeviceUtils { ...@@ -65,4 +66,12 @@ public class DeviceUtils {
DeviceUtils30.logPreviousCrashesIfAny(context); DeviceUtils30.logPreviousCrashesIfAny(context);
} }
} }
public static void vibrate(Vibrator vibrator) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
DeviceUtils26.vibrate(vibrator);
} else {
DeviceUtils23.vibrate(vibrator);
}
}
} }
...@@ -21,6 +21,7 @@ package org.linphone.core.tools.compatibility; ...@@ -21,6 +21,7 @@ package org.linphone.core.tools.compatibility;
import android.content.Context; import android.content.Context;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.Vibrator;
import org.linphone.core.tools.Log; import org.linphone.core.tools.Log;
...@@ -31,4 +32,9 @@ public class DeviceUtils23 { ...@@ -31,4 +32,9 @@ public class DeviceUtils23 {
Log.i("[Platform Helper] Is app in device battery optimization whitelist: " + ignoringBatteryOptimizations); Log.i("[Platform Helper] Is app in device battery optimization whitelist: " + ignoringBatteryOptimizations);
return !ignoringBatteryOptimizations; return !ignoringBatteryOptimizations;
} }
public static void vibrate(Vibrator vibrator) {
long[] pattern = {0, 1000, 1000};
vibrator.vibrate(pattern, 1);
}
} }
...@@ -20,9 +20,23 @@ ...@@ -20,9 +20,23 @@
package org.linphone.core.tools.compatibility; package org.linphone.core.tools.compatibility;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.media.AudioAttributes;
import android.os.Vibrator;
import android.os.VibrationEffect;
public class DeviceUtils26 { public class DeviceUtils26 {
public static boolean isSurfaceTextureReleased(SurfaceTexture surfaceTexture) { public static boolean isSurfaceTextureReleased(SurfaceTexture surfaceTexture) {
return surfaceTexture.isReleased(); return surfaceTexture.isReleased();
} }
public static void vibrate(Vibrator vibrator) {
long[] timings = {0, 1000, 1000};
int[] amplitudes = {0, VibrationEffect.DEFAULT_AMPLITUDE, 0};
VibrationEffect effect = VibrationEffect.createWaveform(timings, amplitudes, 1);
AudioAttributes audioAttrs =
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
vibrator.vibrate(effect, audioAttrs);
}
} }
...@@ -23,18 +23,22 @@ import android.app.Notification; ...@@ -23,18 +23,22 @@ import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.Vibrator;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import org.linphone.core.Call;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub; import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory; import org.linphone.core.Factory;
import org.linphone.core.tools.Log; import org.linphone.core.tools.Log;
import org.linphone.core.tools.compatibility.DeviceUtils;
import org.linphone.mediastream.Version; import org.linphone.mediastream.Version;
/** /**
...@@ -54,6 +58,8 @@ public class CoreService extends Service { ...@@ -54,6 +58,8 @@ public class CoreService extends Service {
protected Notification mServiceNotification = null; protected Notification mServiceNotification = null;
private CoreListenerStub mListener; private CoreListenerStub mListener;
private Vibrator mVibrator;
private boolean mIsVibrating;
@Override @Override
public void onCreate() { public void onCreate() {
...@@ -67,6 +73,8 @@ public class CoreService extends Service { ...@@ -67,6 +73,8 @@ public class CoreService extends Service {
createServiceNotificationChannel(); createServiceNotificationChannel();
} }
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mListener = new CoreListenerStub() { mListener = new CoreListenerStub() {
@Override @Override
public void onFirstCallStarted(Core core) { public void onFirstCallStarted(Core core) {
...@@ -75,6 +83,28 @@ public class CoreService extends Service { ...@@ -75,6 +83,28 @@ public class CoreService extends Service {
if (!mIsInForegroundMode) { if (!mIsInForegroundMode) {
startForeground(); startForeground();
} }
// Starting Android 10 foreground service is a requirement to be able to vibrate if app is in background
if (core.getCurrentCall().getDir() == Call.Dir.Incoming && core.isVibrationOnIncomingCallEnabled()) {
if (mVibrator.hasVibrator()) {
Log.i("[Core Service] Starting vibrator");
DeviceUtils.vibrate(mVibrator);
mIsVibrating = true;
} else {
Log.e("[Core Service] Device doesn't have a vibrator");
}
}
}
@Override
public void onCallStateChanged(Core core, Call call, Call.State state, String message) {
if (state == Call.State.End || state == Call.State.Error || state == Call.State.Connected) {
if (mIsVibrating) {
Log.i("[Core Service] Stopping vibrator");
mVibrator.cancel();
mIsVibrating = false;
}
}
} }
@Override @Override
...@@ -95,6 +125,18 @@ public class CoreService extends Service { ...@@ -95,6 +125,18 @@ public class CoreService extends Service {
if (core.getCallsNb() > 0) { if (core.getCallsNb() > 0) {
Log.w("[Core Service] Service started while at least one call active !"); Log.w("[Core Service] Service started while at least one call active !");
startForeground(); startForeground();
Call call = core.getCurrentCall();
// Starting Android 10 foreground service is a requirement to be able to vibrate if app is in background
if (call.getDir() == Call.Dir.Incoming && call.getState() == Call.State.IncomingReceived && core.isVibrationOnIncomingCallEnabled()) {
if (mVibrator.hasVibrator()) {
Log.i("[Core Service] Starting vibrator");
DeviceUtils.vibrate(mVibrator);
mIsVibrating = true;
} else {
Log.e("[Core Service] Device doesn't have a vibrator");
}
}
} }
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment