diff options
author | Martijn Coenen <maco@google.com> | 2012-09-26 11:04:09 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-09-26 11:04:09 -0700 |
commit | 2e4fc72b81880372344e36cd94e12da6122f7401 (patch) | |
tree | 8cb18035b8b10b088c9ce59b454191e6d420bc9b | |
parent | d7b6ee314f297e1304a02ee6cdc5182586d0e98f (diff) | |
parent | a112f9c00e3337ef38ea8e1715a99db4966c7219 (diff) | |
download | packages_apps_nfc-2e4fc72b81880372344e36cd94e12da6122f7401.zip packages_apps_nfc-2e4fc72b81880372344e36cd94e12da6122f7401.tar.gz packages_apps_nfc-2e4fc72b81880372344e36cd94e12da6122f7401.tar.bz2 |
am a112f9c0: Fix NFC->Bluetooth headset/a2dp connection.
* commit 'a112f9c00e3337ef38ea8e1715a99db4966c7219':
Fix NFC->Bluetooth headset/a2dp connection.
-rw-r--r-- | src/com/android/nfc/handover/BluetoothHeadsetHandover.java | 223 | ||||
-rw-r--r-- | src/com/android/nfc/handover/HandoverManager.java | 43 |
2 files changed, 159 insertions, 107 deletions
diff --git a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java index 7974dfa..644ecbd 100644 --- a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java +++ b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java @@ -44,9 +44,8 @@ import com.android.nfc.R; * designed to be re-used after the sequence has completed or timed out. * Subsequent NFC interactions should use new objects. * - * TODO: UI review */ -public class BluetoothHeadsetHandover { +public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListener { static final String TAG = HandoverManager.TAG; static final boolean DBG = HandoverManager.DBG; @@ -57,28 +56,33 @@ public class BluetoothHeadsetHandover { static final int STATE_INIT = 0; static final int STATE_TURNING_ON = 1; - static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 2; - static final int STATE_BONDING = 3; - static final int STATE_CONNECTING = 4; - static final int STATE_DISCONNECTING = 5; - static final int STATE_COMPLETE = 6; + static final int STATE_WAITING_FOR_PROXIES = 2; + static final int STATE_INIT_COMPLETE = 3; + static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 4; + static final int STATE_BONDING = 5; + static final int STATE_CONNECTING = 6; + static final int STATE_DISCONNECTING = 7; + static final int STATE_COMPLETE = 8; static final int RESULT_PENDING = 0; static final int RESULT_CONNECTED = 1; static final int RESULT_DISCONNECTED = 2; + static final int ACTION_INIT = 0; static final int ACTION_DISCONNECT = 1; static final int ACTION_CONNECT = 2; static final int MSG_TIMEOUT = 1; + static final int MSG_NEXT_STEP = 2; final Context mContext; final BluetoothDevice mDevice; final String mName; final HandoverPowerManager mHandoverPowerManager; - final BluetoothA2dp mA2dp; - final BluetoothHeadset mHeadset; final Callback mCallback; + final BluetoothAdapter mBluetoothAdapter; + + final Object mLock = new Object(); // only used on main thread int mAction; @@ -86,21 +90,24 @@ public class BluetoothHeadsetHandover { int mHfpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING + // protected by mLock + BluetoothA2dp mA2dp; + BluetoothHeadset mHeadset; + public interface Callback { public void onBluetoothHeadsetHandoverComplete(boolean connected); } public BluetoothHeadsetHandover(Context context, BluetoothDevice device, String name, - HandoverPowerManager powerManager, BluetoothA2dp a2dp, BluetoothHeadset headset, - Callback callback) { + HandoverPowerManager powerManager, Callback callback) { checkMainThread(); // mHandler must get get constructed on Main Thread for toasts to work mContext = context; mDevice = device; mName = name; mHandoverPowerManager = powerManager; - mA2dp = a2dp; - mHeadset = headset; mCallback = callback; + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mState = STATE_INIT; } @@ -111,6 +118,7 @@ public class BluetoothHeadsetHandover { public void start() { checkMainThread(); if (mState != STATE_INIT) return; + if (mBluetoothAdapter == null) return; IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); @@ -122,15 +130,8 @@ public class BluetoothHeadsetHandover { mContext.registerReceiver(mReceiver, filter); - if (mA2dp.getConnectedDevices().contains(mDevice) || - mHeadset.getConnectedDevices().contains(mDevice)) { - Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName); - mAction = ACTION_DISCONNECT; - } else { - Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName); - mAction = ACTION_CONNECT; - } mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS); + mAction = ACTION_INIT; nextStep(); } @@ -138,35 +139,83 @@ public class BluetoothHeadsetHandover { * Called to execute next step in state machine */ void nextStep() { - if (mAction == ACTION_CONNECT) { + if (mAction == ACTION_INIT) { + nextStepInit(); + } else if (mAction == ACTION_CONNECT) { nextStepConnect(); } else { nextStepDisconnect(); } } - void nextStepDisconnect() { + /* + * Enables bluetooth and gets the profile proxies + */ + void nextStepInit() { switch (mState) { case STATE_INIT: - mState = STATE_DISCONNECTING; - if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { - mHfpResult = RESULT_PENDING; - mHeadset.disconnect(mDevice); - } else { - mHfpResult = RESULT_DISCONNECTED; - } - if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { - mA2dpResult = RESULT_PENDING; - mA2dp.disconnect(mDevice); - } else { - mA2dpResult = RESULT_DISCONNECTED; + if (!mHandoverPowerManager.isBluetoothEnabled()) { + if (mHandoverPowerManager.enableBluetooth()) { + // Bluetooth is being enabled + mState = STATE_TURNING_ON; + } else { + toast(mContext.getString(R.string.failed_to_enable_bt)); + complete(false); + } + break; } - if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { - toast(mContext.getString(R.string.disconnecting_headset ) + " " + - mName + "..."); + // fall-through + case STATE_TURNING_ON: + if (mA2dp == null || mHeadset == null) { + mState = STATE_WAITING_FOR_PROXIES; + if (!getProfileProxys()) { + complete(false); + } break; } // fall-through + case STATE_WAITING_FOR_PROXIES: + mState = STATE_INIT_COMPLETE; + // Check connected devices and see if we need to disconnect + synchronized(mLock) { + if (mA2dp.getConnectedDevices().contains(mDevice) || + mHeadset.getConnectedDevices().contains(mDevice)) { + Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName); + mAction = ACTION_DISCONNECT; + } else { + Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName); + mAction = ACTION_CONNECT; + } + } + nextStep(); + } + + } + + void nextStepDisconnect() { + switch (mState) { + case STATE_INIT_COMPLETE: + mState = STATE_DISCONNECTING; + synchronized (mLock) { + if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { + mHfpResult = RESULT_PENDING; + mHeadset.disconnect(mDevice); + } else { + mHfpResult = RESULT_DISCONNECTED; + } + if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { + mA2dpResult = RESULT_PENDING; + mA2dp.disconnect(mDevice); + } else { + mA2dpResult = RESULT_DISCONNECTED; + } + if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { + toast(mContext.getString(R.string.disconnecting_headset ) + " " + + mName + "..."); + break; + } + } + // fall-through case STATE_DISCONNECTING: if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { // still disconnecting @@ -178,26 +227,26 @@ public class BluetoothHeadsetHandover { complete(false); break; } + + } + + boolean getProfileProxys() { + if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET)) + return false; + + if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP)) + return false; + + return true; } void nextStepConnect() { switch (mState) { - case STATE_INIT: - if (!mHandoverPowerManager.isBluetoothEnabled()) { - if (mHandoverPowerManager.enableBluetooth()) { - // Bluetooth is being enabled - mState = STATE_TURNING_ON; - } else { - toast(mContext.getString(R.string.failed_to_enable_bt)); - complete(false); - } - break; - } - // fall-through - case STATE_TURNING_ON: + case STATE_INIT_COMPLETE: if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) { requestPairConfirmation(); mState = STATE_WAITING_FOR_BOND_CONFIRMATION; + break; } // fall-through @@ -211,21 +260,23 @@ public class BluetoothHeadsetHandover { // Bluetooth Profile service will correctly serialize // HFP then A2DP connect mState = STATE_CONNECTING; - if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { - mHfpResult = RESULT_PENDING; - mHeadset.connect(mDevice); - } else { - mHfpResult = RESULT_CONNECTED; - } - if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { - mA2dpResult = RESULT_PENDING; - mA2dp.connect(mDevice); - } else { - mA2dpResult = RESULT_CONNECTED; - } - if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { - toast(mContext.getString(R.string.connecting_headset) + " " + mName + "..."); - break; + synchronized (mLock) { + if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { + mHfpResult = RESULT_PENDING; + mHeadset.connect(mDevice); + } else { + mHfpResult = RESULT_CONNECTED; + } + if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { + mA2dpResult = RESULT_PENDING; + mA2dp.connect(mDevice); + } else { + mA2dpResult = RESULT_CONNECTED; + } + if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { + toast(mContext.getString(R.string.connecting_headset) + " " + mName + "..."); + break; + } } // fall-through case STATE_CONNECTING: @@ -260,7 +311,7 @@ public class BluetoothHeadsetHandover { if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action) && mState == STATE_TURNING_ON) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if (state == BluetoothAdapter.STATE_ON) { - nextStepConnect(); + nextStep(); } else if (state == BluetoothAdapter.STATE_OFF) { toast(mContext.getString(R.string.failed_to_enable_bt)); complete(false); @@ -313,6 +364,16 @@ public class BluetoothHeadsetHandover { mState = STATE_COMPLETE; mContext.unregisterReceiver(mReceiver); mHandler.removeMessages(MSG_TIMEOUT); + synchronized (mLock) { + if (mA2dp != null) { + mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp); + } + if (mHeadset != null) { + mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset); + } + mA2dp = null; + mHeadset = null; + } mCallback.onBluetoothHeadsetHandoverComplete(connected); } @@ -348,6 +409,9 @@ public class BluetoothHeadsetHandover { Log.i(TAG, "Timeout completing BT handover"); complete(false); break; + case MSG_NEXT_STEP: + nextStep(); + break; } } }; @@ -364,4 +428,29 @@ public class BluetoothHeadsetHandover { throw new IllegalThreadStateException("must be called on main thread"); } } + + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + synchronized (mLock) { + switch (profile) { + case BluetoothProfile.HEADSET: + mHeadset = (BluetoothHeadset) proxy; + if (mA2dp != null) { + mHandler.sendEmptyMessage(MSG_NEXT_STEP); + } + break; + case BluetoothProfile.A2DP: + mA2dp = (BluetoothA2dp) proxy; + if (mHeadset != null) { + mHandler.sendEmptyMessage(MSG_NEXT_STEP); + } + break; + } + } + } + + @Override + public void onServiceDisconnected(int profile) { + // We can ignore these + } } diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index b4c2025..a514f85 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -62,8 +62,7 @@ import com.android.nfc.R; /** * Manages handover of NFC to other technologies. */ -public class HandoverManager implements BluetoothProfile.ServiceListener, - BluetoothHeadsetHandover.Callback { +public class HandoverManager implements BluetoothHeadsetHandover.Callback { static final String TAG = "NfcHandover"; static final boolean DBG = true; @@ -142,8 +141,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, // Variables below synchronized on HandoverManager.this final HashMap<Pair<String, Boolean>, HandoverTransfer> mTransfers; - BluetoothHeadset mBluetoothHeadset; - BluetoothA2dp mBluetoothA2dp; BluetoothHeadsetHandover mBluetoothHeadsetHandover; boolean mBluetoothHeadsetConnected; @@ -612,10 +609,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, public HandoverManager(Context context) { mContext = context; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - if (mBluetoothAdapter != null) { - mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET); - mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP); - } mNotificationManager = (NotificationManager) mContext.getSystemService( Context.NOTIFICATION_SERVICE); @@ -792,9 +785,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, if (!handover.valid) return true; synchronized (HandoverManager.this) { - if (mBluetoothAdapter == null || - mBluetoothA2dp == null || - mBluetoothHeadset == null) { + if (mBluetoothAdapter == null) { if (DBG) Log.d(TAG, "BT handover, but BT not available"); return true; } @@ -803,7 +794,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, return true; } mBluetoothHeadsetHandover = new BluetoothHeadsetHandover(mContext, handover.device, - handover.name, mHandoverPowerManager, mBluetoothA2dp, mBluetoothHeadset, this); + handover.name, mHandoverPowerManager, this); mBluetoothHeadsetHandover.start(); } return true; @@ -983,34 +974,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, } @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - synchronized (HandoverManager.this) { - switch (profile) { - case BluetoothProfile.HEADSET: - mBluetoothHeadset = (BluetoothHeadset) proxy; - break; - case BluetoothProfile.A2DP: - mBluetoothA2dp = (BluetoothA2dp) proxy; - break; - } - } - } - - @Override - public void onServiceDisconnected(int profile) { - synchronized (HandoverManager.this) { - switch (profile) { - case BluetoothProfile.HEADSET: - mBluetoothHeadset = null; - break; - case BluetoothProfile.A2DP: - mBluetoothA2dp = null; - break; - } - } - } - - @Override public void onBluetoothHeadsetHandoverComplete(boolean connected) { synchronized (HandoverManager.this) { mBluetoothHeadsetHandover = null; |