Reworked Bluetooth manager for Android 3.0+, working better now
This commit is contained in:
parent
734c3b7625
commit
d73ff36208
3 changed files with 279 additions and 174 deletions
|
@ -17,13 +17,22 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener.AudioState;
|
||||||
|
import org.linphone.compatibility.Compatibility;
|
||||||
import org.linphone.mediastream.Log;
|
import org.linphone.mediastream.Log;
|
||||||
|
import org.linphone.mediastream.Version;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothHeadset;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
@ -32,50 +41,248 @@ import android.os.Build;
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
public class BluetoothManager extends BroadcastReceiver {
|
public class BluetoothManager extends BroadcastReceiver {
|
||||||
|
private static BluetoothManager instance;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private AudioManager mAudioManager;
|
||||||
|
private BluetoothAdapter mBluetoothAdapter;
|
||||||
|
private BluetoothHeadset mBluetoothHeadset;
|
||||||
|
private BluetoothDevice mBluetoothDevice;
|
||||||
|
private BluetoothProfile.ServiceListener mProfileListener;
|
||||||
|
private BroadcastReceiver bluetoothActionReceiver = new BluetoothActionReceiver();
|
||||||
|
private boolean isBluetoothConnected;
|
||||||
|
private boolean isUsingBluetoothAudioRoute;
|
||||||
|
|
||||||
|
public static BluetoothManager getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new BluetoothManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not call !
|
||||||
|
*/
|
||||||
|
public BluetoothManager() {
|
||||||
|
isBluetoothConnected = false;
|
||||||
|
isUsingBluetoothAudioRoute = false;
|
||||||
|
try {
|
||||||
|
mContext = LinphoneManager.getInstance().getContext();
|
||||||
|
mAudioManager = ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE));
|
||||||
|
instance = this;
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startBluetooth() {
|
||||||
|
if (isBluetoothConnected) {
|
||||||
|
Log.e("Bluetooth already started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction("android.bluetooth.device.action.ACL_CONNECTED");
|
||||||
|
filter.addAction("android.bluetooth.device.action.ACL_DISCONNECTED");
|
||||||
|
filter.addAction("android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED");
|
||||||
|
mContext.registerReceiver(this, filter);
|
||||||
|
Log.d("Bluetooth receiver started");
|
||||||
|
|
||||||
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
|
||||||
|
if (mBluetoothAdapter.isEnabled()) {
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
||||||
|
if (mProfileListener != null) {
|
||||||
|
Log.w("Bluetooth headset profile was already opened, let's close it");
|
||||||
|
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
||||||
|
}
|
||||||
|
|
||||||
|
mProfileListener = new BluetoothProfile.ServiceListener() {
|
||||||
|
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||||
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
|
Log.d("Bluetooth headset connected");
|
||||||
|
mContext.registerReceiver(bluetoothActionReceiver, new IntentFilter(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT));
|
||||||
|
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||||
|
isBluetoothConnected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onServiceDisconnected(int profile) {
|
||||||
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
|
mContext.unregisterReceiver(bluetoothActionReceiver);
|
||||||
|
mBluetoothHeadset = null;
|
||||||
|
isBluetoothConnected = false;
|
||||||
|
Log.d("Bluetooth headset disconnected");
|
||||||
|
LinphoneManager.getInstance().routeAudioToSpeaker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
boolean success = mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
|
||||||
|
if (!success) {
|
||||||
|
Log.e("Bluetooth getProfileProxy failed !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("Bluetooth interface disabled on device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean routeAudioToBluetooth() {
|
||||||
|
return routeAudioToBluetooth(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean routeAudioToBluetooth(boolean isRetry) {
|
||||||
|
if (mBluetoothAdapter == null) {
|
||||||
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBluetoothAdapter.isEnabled() && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||||
|
isUsingBluetoothAudioRoute = isBluetoothHeadsetAvailable();
|
||||||
|
|
||||||
|
if (isUsingBluetoothAudioRoute) {
|
||||||
|
if (mAudioManager != null) {
|
||||||
|
mAudioManager.setBluetoothScoOn(true);
|
||||||
|
mAudioManager.startBluetoothSco();
|
||||||
|
LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
isUsingBluetoothAudioRoute = mBluetoothHeadset.isAudioConnected(mBluetoothDevice);
|
||||||
|
if (!isUsingBluetoothAudioRoute && !isRetry) {
|
||||||
|
Log.w("Routing audio to bluetooth headset failed, retry....");
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
return routeAudioToBluetooth(true);
|
||||||
|
} else if (isRetry) {
|
||||||
|
if (isUsingBluetoothAudioRoute) {
|
||||||
|
Log.d("Retry worked, audio is routed to bluetooth headset");
|
||||||
|
} else {
|
||||||
|
Log.e("Retry not worked, audio isn't routed to bluetooth headset...");
|
||||||
|
disableBluetoothSCO();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d("Routing audio to bluetooth headset worked at first try");
|
||||||
|
}
|
||||||
|
|
||||||
|
return isUsingBluetoothAudioRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUsingBluetoothAudioRoute() {
|
||||||
|
return mBluetoothHeadset.isAudioConnected(mBluetoothDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBluetoothHeadsetAvailable() {
|
||||||
|
if (mBluetoothAdapter == null) {
|
||||||
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBluetoothAdapter.isEnabled() && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
||||||
|
boolean isHeadsetConnected = false;
|
||||||
|
if (mBluetoothHeadset != null) {
|
||||||
|
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
|
||||||
|
for (final BluetoothDevice dev : devices) {
|
||||||
|
if (mBluetoothHeadset.getConnectionState(dev) == BluetoothHeadset.STATE_CONNECTED) {
|
||||||
|
mBluetoothDevice = dev;
|
||||||
|
isHeadsetConnected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(isHeadsetConnected ? "Headset found, bluetooth audio route available" : "No headset found, bluetooth audio route unavailable");
|
||||||
|
}
|
||||||
|
return isHeadsetConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableBluetoothSCO() {
|
||||||
|
isUsingBluetoothAudioRoute = false;
|
||||||
|
if (mAudioManager != null) {
|
||||||
|
mAudioManager.stopBluetoothSco();
|
||||||
|
mAudioManager.setBluetoothScoOn(false);
|
||||||
|
Log.w("Bluetooth sco disconnected!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopBluetooth() {
|
||||||
|
Log.w("Stopping bluetooth...");
|
||||||
|
isBluetoothConnected = false;
|
||||||
|
isUsingBluetoothAudioRoute = false;
|
||||||
|
|
||||||
|
if (mAudioManager != null) {
|
||||||
|
mAudioManager.stopBluetoothSco();
|
||||||
|
mAudioManager.setBluetoothScoOn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mProfileListener != null && mBluetoothHeadset != null) {
|
||||||
|
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
||||||
|
mContext.unregisterReceiver(bluetoothActionReceiver);
|
||||||
|
mProfileListener = null;
|
||||||
|
mBluetoothHeadset = null;
|
||||||
|
}
|
||||||
|
mBluetoothDevice = null;
|
||||||
|
|
||||||
|
Log.w("Bluetooth stopped!");
|
||||||
|
|
||||||
|
if (LinphoneManager.getLc().getCallsNb() > 0) {
|
||||||
|
Log.w("Bluetooth disabled, Going back to incall mode");
|
||||||
|
Compatibility.setAudioManagerInCallMode(mAudioManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mContext.unregisterReceiver(this);
|
||||||
|
Log.d("Bluetooth receiver stopped");
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
if (LinphoneManager.isInstanciated()) {
|
||||||
|
LinphoneManager.getInstance().routeAudioToSpeaker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
try {
|
||||||
|
stopBluetooth();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (!LinphoneManager.isInstanciated())
|
if (!LinphoneManager.isInstanciated())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
LinphoneManager lm = LinphoneManager.getInstance();
|
|
||||||
|
|
||||||
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
|
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
|
||||||
Log.e("Bluetooth Received Event" + " ACTION_ACL_DISCONNECTED" );
|
Log.d("Bluetooth Received Event" + " ACTION_ACL_DISCONNECTED");
|
||||||
|
|
||||||
if (lm != null) {
|
stopBluetooth();
|
||||||
lm.scoDisconnected();
|
|
||||||
lm.routeAudioToReceiver();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
|
else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
|
||||||
Log.e("Bluetooth Received Event" + " ACTION_ACL_CONNECTED" );
|
Log.d("Bluetooth Received Event" + " ACTION_ACL_CONNECTED");
|
||||||
|
startBluetooth();
|
||||||
if (lm != null) {
|
|
||||||
lm.scoConnected();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(action)) {
|
else if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(action)) {
|
||||||
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
||||||
Log.e("Bluetooth sco state changed : " + state);
|
Log.d("Bluetooth sco state changed : " + state);
|
||||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||||
if (lm != null) {
|
startBluetooth();
|
||||||
lm.scoConnected();
|
|
||||||
}
|
|
||||||
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||||
if (lm != null) {
|
stopBluetooth();
|
||||||
lm.scoDisconnected();
|
|
||||||
lm.routeAudioToReceiver();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Using real value instead of constant because not available before sdk 11
|
//Using real value instead of constant because not available before sdk 11
|
||||||
else if ("android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED".equals(action)) { //BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED
|
else if ("android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED".equals(action)) { //BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED
|
||||||
int currentConnState = intent.getIntExtra("android.bluetooth.adapter.extra.CONNECTION_STATE", //BluetoothAdapter.EXTRA_CONNECTION_STATE
|
int currentConnState = intent.getIntExtra("android.bluetooth.adapter.extra.CONNECTION_STATE", //BluetoothAdapter.EXTRA_CONNECTION_STATE
|
||||||
0); //BluetoothAdapter.STATE_DISCONNECTED
|
0); //BluetoothAdapter.STATE_DISCONNECTED
|
||||||
Log.e("Bluetooth state changed: " + currentConnState);
|
Log.d("Bluetooth state changed: " + currentConnState);
|
||||||
if (lm != null && currentConnState == 2) { //BluetoothAdapter.STATE_CONNECTED
|
if (currentConnState == 2) { //BluetoothAdapter.STATE_CONNECTED
|
||||||
lm.startBluetooth();
|
startBluetooth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,7 @@ public class InCallActivity extends FragmentActivity implements
|
||||||
slideOutTopToBottom = AnimationUtils.loadAnimation(this, R.anim.slide_out_top_to_bottom);
|
slideOutTopToBottom = AnimationUtils.loadAnimation(this, R.anim.slide_out_top_to_bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LinphoneManager.getInstance().isBluetoothScoConnected) {
|
if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
||||||
try {
|
try {
|
||||||
if (routeLayout != null)
|
if (routeLayout != null)
|
||||||
routeLayout.setVisibility(View.VISIBLE);
|
routeLayout.setVisibility(View.VISIBLE);
|
||||||
|
@ -292,7 +292,7 @@ public class InCallActivity extends FragmentActivity implements
|
||||||
} else {
|
} else {
|
||||||
speaker.setBackgroundResource(R.drawable.speaker_off);
|
speaker.setBackgroundResource(R.drawable.speaker_off);
|
||||||
routeSpeaker.setBackgroundResource(R.drawable.route_speaker_off);
|
routeSpeaker.setBackgroundResource(R.drawable.route_speaker_off);
|
||||||
if (LinphoneManager.getInstance().isUsingBluetoothAudioRoute) {
|
if (BluetoothManager.getInstance().isUsingBluetoothAudioRoute()) {
|
||||||
routeReceiver.setBackgroundResource(R.drawable.route_receiver_off);
|
routeReceiver.setBackgroundResource(R.drawable.route_receiver_off);
|
||||||
routeBluetooth.setBackgroundResource(R.drawable.route_bluetooth_on);
|
routeBluetooth.setBackgroundResource(R.drawable.route_bluetooth_on);
|
||||||
} else {
|
} else {
|
||||||
|
@ -404,12 +404,13 @@ public class InCallActivity extends FragmentActivity implements
|
||||||
hideOrDisplayAudioRoutes();
|
hideOrDisplayAudioRoutes();
|
||||||
}
|
}
|
||||||
else if (id == R.id.routeBluetooth) {
|
else if (id == R.id.routeBluetooth) {
|
||||||
LinphoneManager.getInstance().routeAudioToBluetooth();
|
if (BluetoothManager.getInstance().routeAudioToBluetooth()) {
|
||||||
isSpeakerEnabled = false;
|
isSpeakerEnabled = false;
|
||||||
routeBluetooth.setBackgroundResource(R.drawable.route_bluetooth_on);
|
routeBluetooth.setBackgroundResource(R.drawable.route_bluetooth_on);
|
||||||
routeReceiver.setBackgroundResource(R.drawable.route_receiver_off);
|
routeReceiver.setBackgroundResource(R.drawable.route_receiver_off);
|
||||||
routeSpeaker.setBackgroundResource(R.drawable.route_speaker_off);
|
routeSpeaker.setBackgroundResource(R.drawable.route_speaker_off);
|
||||||
hideOrDisplayAudioRoutes();
|
hideOrDisplayAudioRoutes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (id == R.id.routeReceiver) {
|
else if (id == R.id.routeReceiver) {
|
||||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||||
|
@ -493,9 +494,12 @@ public class InCallActivity extends FragmentActivity implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showVideoView() {
|
private void showVideoView() {
|
||||||
isSpeakerEnabled = true;
|
if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
||||||
LinphoneManager.getInstance().routeAudioToSpeaker();
|
Log.w("Bluetooth not available, using speaker");
|
||||||
speaker.setBackgroundResource(R.drawable.speaker_on);
|
LinphoneManager.getInstance().routeAudioToSpeaker();
|
||||||
|
isSpeakerEnabled = true;
|
||||||
|
speaker.setBackgroundResource(R.drawable.speaker_on);
|
||||||
|
}
|
||||||
video.setBackgroundResource(R.drawable.video_off);
|
video.setBackgroundResource(R.drawable.video_off);
|
||||||
|
|
||||||
LinphoneManager.stopProximitySensorForActivity(InCallActivity.this);
|
LinphoneManager.stopProximitySensorForActivity(InCallActivity.this);
|
||||||
|
@ -547,6 +551,7 @@ public class InCallActivity extends FragmentActivity implements
|
||||||
speaker.setBackgroundResource(R.drawable.speaker_on);
|
speaker.setBackgroundResource(R.drawable.speaker_on);
|
||||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||||
} else {
|
} else {
|
||||||
|
Log.d("Toggle speaker off, routing back to earpiece");
|
||||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||||
speaker.setBackgroundResource(R.drawable.speaker_off);
|
speaker.setBackgroundResource(R.drawable.speaker_off);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,10 +78,6 @@ import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothHeadset;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -143,17 +139,7 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
private int mLastNetworkType=-1;
|
private int mLastNetworkType=-1;
|
||||||
private ConnectivityManager mConnectivityManager;
|
private ConnectivityManager mConnectivityManager;
|
||||||
private Handler mHandler = new Handler();
|
private Handler mHandler = new Handler();
|
||||||
|
|
||||||
private WakeLock mIncallWakeLock;
|
private WakeLock mIncallWakeLock;
|
||||||
|
|
||||||
private BluetoothAdapter mBluetoothAdapter;
|
|
||||||
private BluetoothHeadset mBluetoothHeadset;
|
|
||||||
private BluetoothProfile.ServiceListener mProfileListener;
|
|
||||||
private BroadcastReceiver bluetoothReiceiver = new BluetoothManager();
|
|
||||||
private BroadcastReceiver bluetoothActionReceiver = new BluetoothActionReceiver();
|
|
||||||
public boolean isBluetoothScoConnected;
|
|
||||||
public boolean isUsingBluetoothAudioRoute;
|
|
||||||
private boolean mBluetoothStarted;
|
|
||||||
|
|
||||||
public String wizardLoginViewDomain = null;
|
public String wizardLoginViewDomain = null;
|
||||||
|
|
||||||
|
@ -208,13 +194,8 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
|
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
|
||||||
|
|
||||||
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
||||||
isUsingBluetoothAudioRoute = false;
|
Log.w("Routing audio to " + (speakerOn ? "speaker" : "earpiece") + ", disabling bluetooth audio route");
|
||||||
if (mAudioManager != null && mBluetoothStarted) {
|
BluetoothManager.getInstance().disableBluetoothSCO();
|
||||||
//Compatibility.setAudioManagerInCallMode(mAudioManager);
|
|
||||||
mAudioManager.stopBluetoothSco();
|
|
||||||
mAudioManager.setBluetoothScoOn(false);
|
|
||||||
mBluetoothStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!speakerOn) {
|
if (!speakerOn) {
|
||||||
mLc.enableSpeaker(false);
|
mLc.enableSpeaker(false);
|
||||||
|
@ -222,10 +203,15 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
mLc.enableSpeaker(true);
|
mLc.enableSpeaker(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audioStateChanged(speakerOn ? AudioState.SPEAKER : AudioState.EARPIECE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void audioStateChanged(AudioState state) {
|
||||||
for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
|
for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
|
||||||
listener.onAudioStateChanged(speakerOn ? AudioState.SPEAKER : AudioState.EARPIECE);
|
listener.onAudioStateChanged(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void routeAudioToSpeaker() {
|
public void routeAudioToSpeaker() {
|
||||||
routeAudioToSpeakerHelper(true);
|
routeAudioToSpeakerHelper(true);
|
||||||
}
|
}
|
||||||
|
@ -240,109 +226,9 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
return userAgent.toString();
|
return userAgent.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void routeAudioToReceiver() {
|
public void routeAudioToReceiver() {
|
||||||
routeAudioToSpeakerHelper(false);
|
routeAudioToSpeakerHelper(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void startBluetooth() {
|
|
||||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
if (mBluetoothAdapter.isEnabled()) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
mProfileListener = new BluetoothProfile.ServiceListener() {
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
|
||||||
Log.d("Bluetooth headset connected");
|
|
||||||
mServiceContext.registerReceiver(bluetoothActionReceiver, new IntentFilter(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT));
|
|
||||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
|
||||||
isBluetoothScoConnected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
public void onServiceDisconnected(int profile) {
|
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
|
||||||
mServiceContext.unregisterReceiver(bluetoothActionReceiver);
|
|
||||||
mBluetoothHeadset = null;
|
|
||||||
isBluetoothScoConnected = false;
|
|
||||||
Log.d("Bluetooth headset disconnected");
|
|
||||||
routeAudioToReceiver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mBluetoothAdapter.getProfileProxy(mServiceContext, mProfileListener, BluetoothProfile.HEADSET);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
mServiceContext.unregisterReceiver(bluetoothReiceiver);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
|
|
||||||
Intent currentValue = mServiceContext.registerReceiver(bluetoothReiceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
|
|
||||||
int state = currentValue == null ? 0 : currentValue.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
|
||||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
|
||||||
isBluetoothScoConnected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isBluetoothScoConnected = false;
|
|
||||||
scoDisconnected();
|
|
||||||
routeAudioToReceiver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
public boolean routeAudioToBluetooth() {
|
|
||||||
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
if (bluetoothAdapter.isEnabled() && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
|
||||||
mAudioManager.setBluetoothScoOn(true);
|
|
||||||
mAudioManager.startBluetoothSco();
|
|
||||||
mBluetoothStarted=true;
|
|
||||||
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
isUsingBluetoothAudioRoute = false;
|
|
||||||
if (mBluetoothHeadset != null) {
|
|
||||||
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
|
|
||||||
for (final BluetoothDevice dev : devices) {
|
|
||||||
isUsingBluetoothAudioRoute |= mBluetoothHeadset.getConnectionState(dev) == BluetoothHeadset.STATE_CONNECTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isUsingBluetoothAudioRoute) {
|
|
||||||
Log.d("No bluetooth device available");
|
|
||||||
scoDisconnected();
|
|
||||||
} else {
|
|
||||||
//Why is this for:
|
|
||||||
//mAudioManager.setMode(AudioManager.MODE_IN_CALL);
|
|
||||||
for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
|
|
||||||
listener.onAudioStateChanged(AudioState.SPEAKER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isUsingBluetoothAudioRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scoConnected() {
|
|
||||||
Log.i("Bluetooth sco connected!");
|
|
||||||
isBluetoothScoConnected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scoDisconnected() {
|
|
||||||
Log.w("Bluetooth sco disconnected!");
|
|
||||||
isUsingBluetoothAudioRoute = false;
|
|
||||||
isBluetoothScoConnected = false;
|
|
||||||
if (mAudioManager != null) {
|
|
||||||
//why is this for ?
|
|
||||||
//mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
|
||||||
mAudioManager.stopBluetoothSco();
|
|
||||||
mAudioManager.setBluetoothScoOn(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized static final LinphoneManager createAndStart(Context c, LinphoneServiceListener listener) {
|
public synchronized static final LinphoneManager createAndStart(Context c, LinphoneServiceListener listener) {
|
||||||
if (instance != null)
|
if (instance != null)
|
||||||
|
@ -654,7 +540,7 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
|
|
||||||
updateNetworkReachability();
|
updateNetworkReachability();
|
||||||
|
|
||||||
startBluetooth();
|
BluetoothManager.getInstance().startBluetooth();
|
||||||
resetCameraFromPreferences();
|
resetCameraFromPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,19 +627,7 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
if (LinphoneService.isReady()) // indeed, no need to crash
|
if (LinphoneService.isReady()) // indeed, no need to crash
|
||||||
ChatStorage.getInstance().close();
|
ChatStorage.getInstance().close();
|
||||||
|
|
||||||
try {
|
BluetoothManager.getInstance().destroy();
|
||||||
mServiceContext.unregisterReceiver(bluetoothReiceiver);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mServiceContext.unregisterReceiver(bluetoothActionReceiver);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30))
|
|
||||||
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mTimer.cancel();
|
mTimer.cancel();
|
||||||
mLc.destroy();
|
mLc.destroy();
|
||||||
|
@ -994,6 +868,7 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Hacks.needSoftvolume()) {
|
if (Hacks.needSoftvolume()) {
|
||||||
|
Log.w("Using soft volume audio hack");
|
||||||
adjustVolume(0); // Synchronize
|
adjustVolume(0); // Synchronize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1001,9 +876,9 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
if (state == State.CallReleased || state == State.Error) {
|
if (state == State.CallReleased || state == State.Error) {
|
||||||
if (mLc.getCallsNb() == 0) {
|
if (mLc.getCallsNb() == 0) {
|
||||||
if (mAudioFocused){
|
if (mAudioFocused){
|
||||||
int res=mAudioManager.abandonAudioFocus(null);
|
int res = mAudioManager.abandonAudioFocus(null);
|
||||||
Log.d("Audio focus released a bit later: " + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED ? "Granted" : "Denied"));
|
Log.d("Audio focus released a bit later: " + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED ? "Granted" : "Denied"));
|
||||||
mAudioFocused=false;
|
mAudioFocused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context activity = getContext();
|
Context activity = getContext();
|
||||||
|
@ -1027,7 +902,21 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State.StreamsRunning) {
|
if (state == State.StreamsRunning) {
|
||||||
|
if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
||||||
|
BluetoothManager.getInstance().routeAudioToBluetooth();
|
||||||
|
// Hack for Android 4.2.2: we have to retry later, the first call will fail
|
||||||
|
if (Build.VERSION.SDK_INT == 17) {
|
||||||
|
mHandler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
BluetoothManager.getInstance().routeAudioToBluetooth();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mIncallWakeLock == null) {
|
if (mIncallWakeLock == null) {
|
||||||
mIncallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "incall");
|
mIncallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "incall");
|
||||||
}
|
}
|
||||||
|
@ -1148,7 +1037,10 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
|
|
||||||
isRinging = false;
|
isRinging = false;
|
||||||
// You may need to call galaxys audio hack after this method
|
// You may need to call galaxys audio hack after this method
|
||||||
routeAudioToReceiver();
|
if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
|
||||||
|
Log.d("Stopped ringing, routing back to earpiece");
|
||||||
|
routeAudioToReceiver();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1360,6 +1252,7 @@ public class LinphoneManager implements LinphoneCoreListener {
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
TelephonyManager tm = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
|
TelephonyManager tm = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
if (state == State.CallEnd && mLc.getCallsNb() == 0 && tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
if (state == State.CallEnd && mLc.getCallsNb() == 0 && tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
||||||
|
Log.d("All call terminated, routing back to earpiece");
|
||||||
routeAudioToReceiver();
|
routeAudioToReceiver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue