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; + } }