Add "BT Pairing and Connection Request" retry sequence

Some target devices are slow to react.
This modification is adding retry sequence
to avoid BT Pairing Timeout and Connection failure.

If target device supports only one profile(A2dp or Hfp),
NFC BT handover fails to connect, so we need to check
supported profile of target device

Bug: 32824463
Change-Id: Iadcb873a2d89780fcc632893e59c35f3926bc596
diff --git a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
index ff2e1fb..8602ee2 100644
--- a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
+++ b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
@@ -58,6 +58,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;
@@ -78,6 +80,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;
@@ -95,6 +100,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;
 
     // protected by mLock
@@ -154,6 +160,7 @@
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
 
         mAction = ACTION_INIT;
+        mRetryCount = 0;
 
         nextStep();
 
@@ -341,8 +348,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;
+                            }
                         }
                     }
                 }
@@ -370,7 +382,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));
@@ -399,10 +413,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)) {
@@ -411,8 +430,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)) {
@@ -421,8 +444,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)) {
@@ -442,6 +469,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);
@@ -497,6 +525,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;
             }
         }
     };
@@ -544,4 +582,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);
+        }
+    }
 }