Merge "Add "BT Pairing and Connection Request" retry sequence"
diff --git a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
index a2c41cc..bba4403 100644
--- a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
+++ b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
@@ -60,6 +60,8 @@
     static final String ACTION_DENY_CONNECT = "com.android.nfc.handover.action.DENY_CONNECT";
 
     static final int TIMEOUT_MS = 20000;
+    static final int RETRY_PAIRING_WAIT_TIME_MS = 2000;
+    static final int RETRY_CONNECT_WAIT_TIME_MS = 5000;
 
     static final int STATE_INIT = 0;
     static final int STATE_WAITING_FOR_PROXIES = 1;
@@ -80,6 +82,9 @@
 
     static final int MSG_TIMEOUT = 1;
     static final int MSG_NEXT_STEP = 2;
+    static final int MSG_RETRY = 3;
+
+    static final int MAX_RETRY_COUNT = 3;
 
     final Context mContext;
     final BluetoothDevice mDevice;
@@ -97,6 +102,7 @@
     int mHfpResult;  // used only in STATE_CONNECTING and STATE_DISCONNETING
     int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
     int mHidResult;
+    int mRetryCount;
     OobData mOobData;
     boolean mIsHeadsetAvailable;
     boolean mIsA2dpAvailable;
@@ -169,6 +175,7 @@
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
 
         mAction = ACTION_INIT;
+        mRetryCount = 0;
 
         nextStep();
 
@@ -376,8 +383,13 @@
                             mA2dpResult = RESULT_CONNECTED;
                         }
                         if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
-                            toast(getToastString(R.string.connecting_peripheral));
-                            break;
+                            if (mRetryCount == 0) {
+                                toast(getToastString(R.string.connecting_peripheral));
+                            }
+                            if (mRetryCount < MAX_RETRY_COUNT) {
+                                sendRetryMessage(RETRY_CONNECT_WAIT_TIME_MS);
+                                break;
+                            }
                         }
                     }
                 }
@@ -405,7 +417,9 @@
 
     void startBonding() {
         mState = STATE_BONDING;
-        toast(getToastString(R.string.pairing_peripheral));
+        if (mRetryCount == 0) {
+            toast(getToastString(R.string.pairing_peripheral));
+        }
         if (mOobData != null) {
             if (!mDevice.createBondOutOfBand(mTransport, mOobData)) {
                 toast(getToastString(R.string.pairing_peripheral_failed));
@@ -434,10 +448,15 @@
             int bond = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
                     BluetoothAdapter.ERROR);
             if (bond == BluetoothDevice.BOND_BONDED) {
+                mRetryCount = 0;
                 nextStepConnect();
             } else if (bond == BluetoothDevice.BOND_NONE) {
-                toast(getToastString(R.string.pairing_peripheral_failed));
-                complete(false);
+                if (mRetryCount < MAX_RETRY_COUNT) {
+                    sendRetryMessage(RETRY_PAIRING_WAIT_TIME_MS);
+                } else {
+                    toast(getToastString(R.string.pairing_peripheral_failed));
+                    complete(false);
+                }
             }
         } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
                 (mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
@@ -446,8 +465,12 @@
                 mHfpResult = RESULT_CONNECTED;
                 nextStep();
             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                mHfpResult = RESULT_DISCONNECTED;
-                nextStep();
+                if (mAction == ACTION_CONNECT && mRetryCount < MAX_RETRY_COUNT) {
+                    sendRetryMessage(RETRY_CONNECT_WAIT_TIME_MS);
+                } else {
+                    mHfpResult = RESULT_DISCONNECTED;
+                    nextStep();
+                }
             }
         } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
                 (mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
@@ -456,8 +479,12 @@
                 mA2dpResult = RESULT_CONNECTED;
                 nextStep();
             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                mA2dpResult = RESULT_DISCONNECTED;
-                nextStep();
+                if (mAction == ACTION_CONNECT && mRetryCount < MAX_RETRY_COUNT) {
+                    sendRetryMessage(RETRY_CONNECT_WAIT_TIME_MS);
+                } else {
+                    mA2dpResult = RESULT_DISCONNECTED;
+                    nextStep();
+                }
             }
         } else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
                 (mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
@@ -477,6 +504,7 @@
         mState = STATE_COMPLETE;
         mContext.unregisterReceiver(mReceiver);
         mHandler.removeMessages(MSG_TIMEOUT);
+        mHandler.removeMessages(MSG_RETRY);
         synchronized (mLock) {
             if (mA2dp != null) {
                 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp);
@@ -560,6 +588,16 @@
                 case MSG_NEXT_STEP:
                     nextStep();
                     break;
+                case MSG_RETRY:
+                    mHandler.removeMessages(MSG_RETRY);
+                    if (mState == STATE_BONDING) {
+                        mState = STATE_WAITING_FOR_BOND_CONFIRMATION;
+                    } else if (mState == STATE_CONNECTING) {
+                        mState = STATE_BONDING;
+                    }
+                    mRetryCount++;
+                    nextStepConnect();
+                    break;
             }
         }
     };
@@ -607,4 +645,10 @@
     public void onServiceDisconnected(int profile) {
         // We can ignore these
     }
+
+    void sendRetryMessage(int waitTime) {
+        if (!mHandler.hasMessages(MSG_RETRY)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RETRY), waitTime);
+        }
+    }
 }