From e7ffd988576f8c9a25ec6c97ed3b9e75439bc933 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 26 Mar 2014 17:26:37 +0100 Subject: [PATCH] Fix bluetooth sco connection still active when call ends issue --- AndroidManifest.xml | 7 +- src/org/linphone/BluetoothActionReceiver.java | 54 -------- src/org/linphone/BluetoothManager.java | 115 ++++++++---------- src/org/linphone/LinphoneManager.java | 13 +- 4 files changed, 53 insertions(+), 136 deletions(-) delete mode 100644 src/org/linphone/BluetoothActionReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c6e3ea500..65f00d0da 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -120,11 +120,6 @@ - - - - - @@ -134,8 +129,10 @@ + + diff --git a/src/org/linphone/BluetoothActionReceiver.java b/src/org/linphone/BluetoothActionReceiver.java deleted file mode 100644 index c8a141fef..000000000 --- a/src/org/linphone/BluetoothActionReceiver.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.linphone; - -/* -BluetoothActionReceiver.java -Copyright (C) 2014 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -import org.linphone.mediastream.Log; - -import android.annotation.TargetApi; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Build; - -@TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class BluetoothActionReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) { - BluetoothDevice device = (BluetoothDevice) intent.getExtras().get(BluetoothDevice.EXTRA_DEVICE); - String command = intent.getExtras().getString(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD); - int type = intent.getExtras().getInt(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE); - - Object[] temp = (Object[]) intent.getExtras().get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS); - String[] args = new String[temp.length]; - String logArgs = ""; - for (int i = 0; i < temp.length; i++) { - args[i] = (String) temp[i]; - logArgs += args[i] + " "; - } - - Log.d("Bluetooth headset event from " + device.getName() + ", command: " + command + " (type: " + type + ") with args: " + logArgs); - - //TODO: parse command/args and do something with it - } - } -} diff --git a/src/org/linphone/BluetoothManager.java b/src/org/linphone/BluetoothManager.java index 19737fb3c..5186b0e82 100644 --- a/src/org/linphone/BluetoothManager.java +++ b/src/org/linphone/BluetoothManager.java @@ -20,12 +20,12 @@ 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.Version; import android.annotation.TargetApi; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothAssignedNumbers; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; @@ -49,9 +49,7 @@ public class BluetoothManager extends BroadcastReceiver { 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) { @@ -60,17 +58,11 @@ public class BluetoothManager extends BroadcastReceiver { return instance; } - /** - * Do not call ! - */ - public BluetoothManager() { + private BluetoothManager() { isBluetoothConnected = false; - isUsingBluetoothAudioRoute = false; - try { - mContext = LinphoneManager.getInstance().getContext(); - mAudioManager = ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)); - instance = this; - } catch (Exception e) {} + mContext = LinphoneManager.getInstance().getContext(); + mAudioManager = ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)); + instance = this; } public void startBluetooth() { @@ -80,9 +72,9 @@ public class BluetoothManager extends BroadcastReceiver { } 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"); + filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." + BluetoothAssignedNumbers.PLANTRONICS); + filter.addAction("android.media.ACTION_SCO_AUDIO_STATE_UPDATED"); + filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT); mContext.registerReceiver(this, filter); Log.d("Bluetooth receiver started"); @@ -99,14 +91,12 @@ public class BluetoothManager extends BroadcastReceiver { 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"); @@ -134,27 +124,22 @@ public class BluetoothManager extends BroadcastReceiver { } if (mBluetoothAdapter.isEnabled() && mAudioManager.isBluetoothScoAvailableOffCall()) { - isUsingBluetoothAudioRoute = isBluetoothHeadsetAvailable(); - - if (isUsingBluetoothAudioRoute) { - if (mAudioManager != null) { + if (isBluetoothHeadsetAvailable()) { + if (mAudioManager != null && !mAudioManager.isBluetoothScoOn()) { mAudioManager.setBluetoothScoOn(true); mAudioManager.startBluetoothSco(); - LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH); } - } else { - LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER); } - isUsingBluetoothAudioRoute = mBluetoothHeadset.isAudioConnected(mBluetoothDevice); - if (!isUsingBluetoothAudioRoute && !isRetry) { + boolean ok = mBluetoothHeadset != null && mBluetoothHeadset.isAudioConnected(mBluetoothDevice); + if (!ok && !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) { + if (ok) { Log.d("Retry worked, audio is routed to bluetooth headset"); } else { Log.e("Retry not worked, audio isn't routed to bluetooth headset..."); @@ -164,14 +149,14 @@ public class BluetoothManager extends BroadcastReceiver { Log.d("Routing audio to bluetooth headset worked at first try"); } - return isUsingBluetoothAudioRoute; + return ok; } return false; } public boolean isUsingBluetoothAudioRoute() { - return mBluetoothHeadset.isAudioConnected(mBluetoothDevice); + return mBluetoothHeadset != null && mBluetoothHeadset.isAudioConnected(mBluetoothDevice); } public boolean isBluetoothHeadsetAvailable() { @@ -183,7 +168,8 @@ public class BluetoothManager extends BroadcastReceiver { if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) { boolean isHeadsetConnected = false; if (mBluetoothHeadset != null) { - List devices = mBluetoothHeadset.getConnectedDevices(); + List devices = mBluetoothHeadset.getConnectedDevices(); + mBluetoothDevice = null; for (final BluetoothDevice dev : devices) { if (mBluetoothHeadset.getConnectionState(dev) == BluetoothHeadset.STATE_CONNECTED) { mBluetoothDevice = dev; @@ -201,8 +187,10 @@ public class BluetoothManager extends BroadcastReceiver { } public void disableBluetoothSCO() { - isUsingBluetoothAudioRoute = false; - if (mAudioManager != null) { + if (mAudioManager != null && mAudioManager.isBluetoothScoOn()) { + mAudioManager.stopBluetoothSco(); + mAudioManager.setBluetoothScoOn(false); + Log.w("Hack: stopping bluetooth sco again since first time won't have succedded"); mAudioManager.stopBluetoothSco(); mAudioManager.setBluetoothScoOn(false); Log.w("Bluetooth sco disconnected!"); @@ -212,28 +200,17 @@ public class BluetoothManager extends BroadcastReceiver { public void stopBluetooth() { Log.w("Stopping bluetooth..."); isBluetoothConnected = false; - isUsingBluetoothAudioRoute = false; - if (mAudioManager != null) { - mAudioManager.stopBluetoothSco(); - mAudioManager.setBluetoothScoOn(false); - } + disableBluetoothSCO(); 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"); @@ -252,38 +229,42 @@ public class BluetoothManager extends BroadcastReceiver { } } - @SuppressWarnings("deprecation") public void onReceive(Context context, Intent intent) { if (!LinphoneManager.isInstanciated()) return; String action = intent.getAction(); - if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { - Log.d("Bluetooth Received Event" + " ACTION_ACL_DISCONNECTED"); - - stopBluetooth(); - } - else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) { - Log.d("Bluetooth Received Event" + " ACTION_ACL_CONNECTED"); - startBluetooth(); - } - else if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(action)) { + //Using real value instead of constant because not available before sdk 11 + if ("android.media.ACTION_SCO_AUDIO_STATE_UPDATED".equals(action)) { // AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0); - Log.d("Bluetooth sco state changed : " + state); - if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) { - startBluetooth(); + if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) { + Log.d("Bluetooth sco state updated to connected"); + LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH); + //isUsingBluetoothAudioRoute = true; } else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) { - stopBluetooth(); + Log.d("Bluetooth sco state updated to disconnected"); + LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER); + //isUsingBluetoothAudioRoute = false; } } - //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 - int currentConnState = intent.getIntExtra("android.bluetooth.adapter.extra.CONNECTION_STATE", //BluetoothAdapter.EXTRA_CONNECTION_STATE + int state = intent.getIntExtra("android.bluetooth.adapter.extra.CONNECTION_STATE", //BluetoothAdapter.EXTRA_CONNECTION_STATE 0); //BluetoothAdapter.STATE_DISCONNECTED - Log.d("Bluetooth state changed: " + currentConnState); - if (currentConnState == 2) { //BluetoothAdapter.STATE_CONNECTED - startBluetooth(); - } - } + if (state == 0) { + Log.d("Bluetooth state updated to disconnected"); + } else if (state == 2) { + Log.d("Bluetooth state updated to connected"); + } + } + else if (intent.getAction().equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) { + String command = intent.getExtras().getString(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD); + int type = intent.getExtras().getInt(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE); + + Object[] args = (Object[]) intent.getExtras().get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS); + String eventName = (String) args[0]; + Log.d("Bluetooth event: " + command + " (type: " + type + ") = " + eventName); + + //TODO: parse command/args and do something with it + } } } diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java index 9ede82a2a..6c5f4dd86 100644 --- a/src/org/linphone/LinphoneManager.java +++ b/src/org/linphone/LinphoneManager.java @@ -885,8 +885,10 @@ public class LinphoneManager implements LinphoneCoreListener { if (activity != null) { TelephonyManager tm = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE); if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { - mAudioManager.setMode(AudioManager.MODE_NORMAL); Log.d("---AudioManager: back to MODE_NORMAL"); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + Log.d("All call terminated, routing back to earpiece"); + routeAudioToReceiver(); } } } @@ -1248,15 +1250,6 @@ public class LinphoneManager implements LinphoneCoreListener { enableCamera(call, sendCamera); } - Context activity = getContext(); - if (activity != null) { - TelephonyManager tm = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE); - if (state == State.CallEnd && mLc.getCallsNb() == 0 && tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { - Log.d("All call terminated, routing back to earpiece"); - routeAudioToReceiver(); - } - } - if (serviceListener != null) serviceListener.onCallStateChanged(call, state, message); for (LinphoneOnCallStateChangedListener l : getSimpleListeners(LinphoneOnCallStateChangedListener.class)) { l.onCallStateChanged(call, state, message);