diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3551088b3..5bd7366bd 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,6 +19,9 @@
+
+
+
diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml
index 7b7a4dc64..2e422e260 100644
--- a/res/values/non_localizable_strings.xml
+++ b/res/values/non_localizable_strings.xml
@@ -45,6 +45,7 @@
first_launch_suceeded_once_key
pref_wifi_only_key
+ pref_use_bluetooth_if_available_key
pref_video_use_front_camera_key
pref_video_codec_h263_key
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 76a823161..6042c6c71 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -240,6 +240,8 @@
SIP Accounts
Use wifi only
+ Use bluetooth headset
+ Route incoming audio to bluetooth headset if available.
An error occurred, try again later.
Server unreachable, verify your internet connection.
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 6ec2d3d6f..260602314 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -56,6 +56,10 @@
+
+
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index ea89b59a3..434ec34e4 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -49,6 +49,7 @@ import java.util.TimerTask;
import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener;
import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener.AudioState;
import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
+import org.linphone.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
@@ -195,33 +196,37 @@ public final class LinphoneManager implements LinphoneCoreListener {
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
private native void hackSpeakerState(boolean speakerOn);
- private static void sRouteAudioToSpeakerHelperHelper(boolean speakerOn) {
- getInstance().routeAudioToSpeakerHelperHelper(speakerOn);
+ private static void sRouteAudioToSpeakerOrBluetoothHelper(boolean speakerOn) {
+ getInstance().routeAudioToSpeakerOrBluetoothHelper(speakerOn);
}
@SuppressWarnings("deprecation")
- private void routeAudioToSpeakerHelperHelper(boolean speakerOn) {
+ private void routeAudioToSpeakerOrBluetoothHelper(boolean speakerOn) {
boolean different = isSpeakerOn() ^ speakerOn;
if (!different) {
Log.d("Skipping change audio route by the same route ",
speakerOn ? "speaker" : "earpiece");
return;
}
- if (Hacks.needGalaxySAudioHack() || sLPref.useGalaxySHack())
- setAudioModeIncallForGalaxyS();
-
- if (sLPref.useSpecificAudioModeHack() != -1)
- mAudioManager.setMode(sLPref.useSpecificAudioModeHack());
-
- if (Hacks.needRoutingAPI() || sLPref.useAudioRoutingAPIHack()) {
- mAudioManager.setRouting(
- MODE_NORMAL,
- speakerOn? ROUTE_SPEAKER : ROUTE_EARPIECE,
- AudioManager.ROUTE_ALL);
+ if (mPref.getBoolean(getString(R.string.pref_use_bluetooth_if_available), true) && Compatibility.enableBluetoothHeadset(mAudioManager)) {
+ return;
} else {
- mAudioManager.setSpeakerphoneOn(speakerOn);
- }
- for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
- listener.onAudioStateChanged(speakerOn ? AudioState.SPEAKER : AudioState.EARPIECE);
+ if (Hacks.needGalaxySAudioHack() || sLPref.useGalaxySHack())
+ setAudioModeIncallForGalaxyS();
+
+ if (sLPref.useSpecificAudioModeHack() != -1)
+ mAudioManager.setMode(sLPref.useSpecificAudioModeHack());
+
+ if (Hacks.needRoutingAPI() || sLPref.useAudioRoutingAPIHack()) {
+ mAudioManager.setRouting(
+ MODE_NORMAL,
+ speakerOn? ROUTE_SPEAKER : ROUTE_EARPIECE,
+ AudioManager.ROUTE_ALL);
+ } else {
+ mAudioManager.setSpeakerphoneOn(speakerOn);
+ }
+ for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
+ listener.onAudioStateChanged(speakerOn ? AudioState.SPEAKER : AudioState.EARPIECE);
+ }
}
}
private synchronized void routeAudioToSpeakerHelper(boolean speakerOn) {
@@ -230,7 +235,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
Log.d("Hack to have speaker=",speakerOn," while on call");
hackSpeakerState(speakerOn);
} else {
- routeAudioToSpeakerHelperHelper(speakerOn);
+ routeAudioToSpeakerOrBluetoothHelper(speakerOn);
}
}
diff --git a/src/org/linphone/PreferencesActivity.java b/src/org/linphone/PreferencesActivity.java
index c37b75159..ea0561093 100644
--- a/src/org/linphone/PreferencesActivity.java
+++ b/src/org/linphone/PreferencesActivity.java
@@ -28,6 +28,7 @@ import static org.linphone.R.string.pref_echo_cancellation_key;
import static org.linphone.R.string.pref_echo_canceller_calibration_key;
import static org.linphone.R.string.pref_echo_limiter_key;
import static org.linphone.R.string.pref_media_encryption_key;
+import static org.linphone.R.string.pref_use_bluetooth_if_available_key;
import static org.linphone.R.string.pref_video_enable_key;
import java.util.ArrayList;
@@ -258,6 +259,10 @@ public class PreferencesActivity extends LinphonePreferencesActivity implements
//findPreference(pref_codec_speex32_key)).setEnabled(enableIlbc);
}
findPreference(pref_echo_limiter_key).setEnabled(true);
+
+ if (!Version.sdkAboveOrEqual(8)) {
+ uncheckAndDisableCheckbox(pref_use_bluetooth_if_available_key);
+ }
initializeMediaEncryptionPreferences();
diff --git a/src/org/linphone/compatibility/ApiEightPlus.java b/src/org/linphone/compatibility/ApiEightPlus.java
index b5c5df28b..ae460e11d 100644
--- a/src/org/linphone/compatibility/ApiEightPlus.java
+++ b/src/org/linphone/compatibility/ApiEightPlus.java
@@ -1,6 +1,7 @@
package org.linphone.compatibility;
import android.annotation.TargetApi;
+import android.media.AudioManager;
import android.view.Display;
/*
@@ -30,4 +31,14 @@ public class ApiEightPlus {
public static int getRotation(Display display) {
return display.getRotation();
}
+
+ public static boolean enableBluetoothHeadset(AudioManager mAudioManager) {
+ if (mAudioManager.isBluetoothScoAvailableOffCall()){
+ mAudioManager.setBluetoothScoOn(true);
+ mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+ mAudioManager.startBluetoothSco();
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java
index c9cb6c0b1..d09de073a 100644
--- a/src/org/linphone/compatibility/Compatibility.java
+++ b/src/org/linphone/compatibility/Compatibility.java
@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
+import android.media.AudioManager;
import android.net.Uri;
import android.view.Display;
import android.view.Window;
@@ -183,4 +184,11 @@ public class Compatibility {
ApiFivePlus.setFullScreen(window);
}
}
+
+ public static boolean enableBluetoothHeadset(AudioManager mAudioManager) {
+ if (Version.sdkAboveOrEqual(8)) {
+ return ApiEightPlus.enableBluetoothHeadset(mAudioManager);
+ }
+ return false;
+ }
}