summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xnci/jni/NativeNfcManager.cpp15
-rw-r--r--src/com/android/nfc/handover/BluetoothHeadsetHandover.java223
-rw-r--r--src/com/android/nfc/handover/HandoverManager.java43
3 files changed, 170 insertions, 111 deletions
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
index 5fd3025..f4d5573 100755
--- a/nci/jni/NativeNfcManager.cpp
+++ b/nci/jni/NativeNfcManager.cpp
@@ -109,6 +109,7 @@ static SyncEvent sNfaSetConfigEvent; // event for Set_Config....
static bool sIsNfaEnabled = false;
static bool sDiscoveryEnabled = false; //is polling for tag?
static bool sIsDisabling = false;
+static bool sRfEnabled = false; // whether RF discovery is enabled
#define NFA_DM_PWR_STATE_UNKNOWN (-1) // power off sleep state is unkown until is is reported back from NFA...
static int sConnlessSap = 0;
static int sConnlessLinkMiu = 0;
@@ -766,6 +767,11 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o)
PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+ if (sRfEnabled) {
+ // Stop RF discovery to reconfigure
+ startRfDiscovery(false);
+ }
+
{
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
stat = NFA_EnablePolling (tech_mask);
@@ -1159,11 +1165,12 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o)
{
ALOGD ("%s: enter", __FUNCTION__);
bool stat = true;
-
PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
- // Stop RF Discovery.
- startRfDiscovery (false);
+ if (sRfEnabled) {
+ // Stop RF Discovery if we were polling
+ startRfDiscovery (false);
+ }
if (sIsSecElemSelected)
{
@@ -1177,7 +1184,6 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o)
sIsSecElemSelected = true;
TheEnd:
- // Restart RF Discovery.
startRfDiscovery (true);
ALOGD ("%s: exit", __FUNCTION__);
@@ -1581,6 +1587,7 @@ void startRfDiscovery(bool isStart)
if (status == NFA_STATUS_OK)
{
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT
+ sRfEnabled = isStart;
}
else
{
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;