am b390728b: am a224f70b: Fix interaction between BluetoothEventLoop and BluetoothService.

Merge commit 'b390728b54805ecba3e0690edf2b83b60933e6a7'

* commit 'b390728b54805ecba3e0690edf2b83b60933e6a7':
  Fix interaction between BluetoothEventLoop and BluetoothService.
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 796aee8..ab79aaf 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -59,22 +59,14 @@
     // from remote device when Android is in Suspend state.
     private PowerManager.WakeLock mWakeLock;
 
-    private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
-    private static final int EVENT_RESTART_BLUETOOTH = 2;
-    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3;
-    private static final int EVENT_AGENT_CANCEL = 4;
+    private static final int EVENT_RESTART_BLUETOOTH = 1;
+    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
+    private static final int EVENT_AGENT_CANCEL = 3;
 
     private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
     private static final int CREATE_DEVICE_SUCCESS = 0;
     private static final int CREATE_DEVICE_FAILED = -1;
 
-    // The time (in millisecs) to delay the pairing attempt after the first
-    // auto pairing attempt fails. We use an exponential delay with
-    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
-    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
-    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
-    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
-
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
 
@@ -83,13 +75,6 @@
         public void handleMessage(Message msg) {
             String address = null;
             switch (msg.what) {
-            case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
-                address = (String)msg.obj;
-                if (address != null) {
-                    mBluetoothService.createBond(address);
-                    return;
-                }
-                break;
             case EVENT_RESTART_BLUETOOTH:
                 mBluetoothService.restart();
                 break;
@@ -102,8 +87,7 @@
             case EVENT_AGENT_CANCEL:
                 // Set the Bond State to BOND_NONE.
                 // We always have only 1 device in BONDING state.
-                String[] devices =
-                    mBluetoothService.getBondState().listInState(BluetoothDevice.BOND_BONDING);
+                String[] devices = mBluetoothService.listInState(BluetoothDevice.BOND_BONDING);
                 if (devices.length == 0) {
                     break;
                 } else if (devices.length > 1) {
@@ -111,7 +95,7 @@
                     break;
                 }
                 address = devices[0];
-                mBluetoothService.getBondState().setBondState(address,
+                mBluetoothService.setBondState(address,
                         BluetoothDevice.BOND_NONE,
                         BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED);
                 break;
@@ -122,7 +106,7 @@
     static { classInitNative(); }
     private static native void classInitNative();
 
-    /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+    /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
             BluetoothService bluetoothService) {
         mBluetoothService = bluetoothService;
         mContext = context;
@@ -221,55 +205,7 @@
 
     private void onCreatePairedDeviceResult(String address, int result) {
         address = address.toUpperCase();
-        if (result == BluetoothDevice.BOND_SUCCESS) {
-            mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
-            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-                mBluetoothService.getBondState().clearPinAttempts(address);
-            }
-        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
-                mBluetoothService.getBondState().getAttempt(address) == 1) {
-            mBluetoothService.getBondState().addAutoPairingFailure(address);
-            pairingAttempt(address, result);
-        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
-                mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-            pairingAttempt(address, result);
-        } else {
-            mBluetoothService.getBondState().setBondState(address,
-                                                          BluetoothDevice.BOND_NONE, result);
-            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-                mBluetoothService.getBondState().clearPinAttempts(address);
-            }
-        }
-    }
-
-    private void pairingAttempt(String address, int result) {
-        // This happens when our initial guess of "0000" as the pass key
-        // fails. Try to create the bond again and display the pin dialog
-        // to the user. Use back-off while posting the delayed
-        // message. The initial value is
-        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
-        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
-        // reached, display an error to the user.
-        int attempt = mBluetoothService.getBondState().getAttempt(address);
-        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
-                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
-            mBluetoothService.getBondState().clearPinAttempts(address);
-            mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NONE, result);
-            return;
-        }
-
-        Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
-        message.obj = address;
-        boolean postResult =  mHandler.sendMessageDelayed(message,
-                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
-        if (!postResult) {
-            mBluetoothService.getBondState().clearPinAttempts(address);
-            mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NONE, result);
-            return;
-        }
-        mBluetoothService.getBondState().attempt(address);
+        mBluetoothService.onCreatePairedDeviceResult(address, result);
     }
 
     private void onDeviceCreated(String deviceObjectPath) {
@@ -287,8 +223,8 @@
     private void onDeviceRemoved(String deviceObjectPath) {
         String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
         if (address != null) {
-            mBluetoothService.getBondState().setBondState(address.toUpperCase(),
-                    BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
+            mBluetoothService.setBondState(address.toUpperCase(), BluetoothDevice.BOND_NONE,
+                BluetoothDevice.UNBOND_REASON_REMOVED);
             mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
         }
     }
@@ -420,13 +356,11 @@
                 // If locally initiated pairing, we will
                 // not go to BOND_BONDED state until we have received a
                 // successful return value in onCreatePairedDeviceResult
-                if (null == mBluetoothService.getBondState().getPendingOutgoingBonding()) {
-                    mBluetoothService.getBondState().setBondState(address,
-                            BluetoothDevice.BOND_BONDED);
+                if (null == mBluetoothService.getPendingOutgoingBonding()) {
+                    mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDED);
                 }
             } else {
-                mBluetoothService.getBondState().setBondState(address,
-                        BluetoothDevice.BOND_NONE);
+                mBluetoothService.setBondState(address, BluetoothDevice.BOND_NONE);
                 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
             }
         } else if (name.equals("Trusted")) {
@@ -494,8 +428,8 @@
         // Also set it only when the state is not already Bonded, we can sometimes
         // get an authorization request from the remote end if it doesn't have the link key
         // while we still have it.
-        if (mBluetoothService.getBondState().getBondState(address) != BluetoothDevice.BOND_BONDED)
-            mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
+        if (mBluetoothService.getBondState(address) != BluetoothDevice.BOND_BONDED)
+            mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDING);
         return address;
     }
 
@@ -509,7 +443,7 @@
          * so we may get this request many times. Also if we respond immediately,
          * the other end is unable to handle it. Delay sending the message.
          */
-        if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) {
+        if (mBluetoothService.getBondState(address) == BluetoothDevice.BOND_BONDED) {
             Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
             message.obj = address;
             mHandler.sendMessageDelayed(message, 1500);
@@ -563,7 +497,7 @@
         if (address == null) return;
 
         String pendingOutgoingAddress =
-                mBluetoothService.getBondState().getPendingOutgoingBonding();
+                mBluetoothService.getPendingOutgoingBonding();
         if (address.equals(pendingOutgoingAddress)) {
             // we initiated the bonding
 
@@ -584,12 +518,7 @@
             case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
-                if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
-                    !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
-                    mBluetoothService.getBondState().attempt(address);
-                    mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
-                    return;
-                }
+                if (mBluetoothService.attemptAutoPair(address)) return;
            }
         }
         // Acquire wakelock during PIN code request to bring up LCD display
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index f8fcdb5..7f160c4 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -113,6 +113,14 @@
     private static final int MESSAGE_FINISH_DISABLE = 2;
     private static final int MESSAGE_UUID_INTENT = 3;
     private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
+    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5;
+
+    // The time (in millisecs) to delay the pairing attempt after the first
+    // auto pairing attempt fails. We use an exponential delay with
+    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
 
     private ArrayList<String> mBluetoothIfaceAddresses;
     private int mMaxPanDevices;
@@ -536,6 +544,13 @@
                     setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
                 }
                 break;
+            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+                address = (String)msg.obj;
+                if (address != null) {
+                    createBond(address);
+                    return;
+                }
+                break;
             }
         }
     };
@@ -629,8 +644,68 @@
         Binder.restoreCallingIdentity(origCallerIdentityToken);
     }
 
-    /* package */ BondState getBondState() {
-        return mBondState;
+    /*package*/ synchronized boolean attemptAutoPair(String address) {
+        if (!mBondState.hasAutoPairingFailed(address) &&
+                !mBondState.isAutoPairingBlacklisted(address)) {
+            mBondState.attempt(address);
+            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
+            return true;
+        }
+        return false;
+    }
+
+    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
+        if (result == BluetoothDevice.BOND_SUCCESS) {
+            setBondState(address, BluetoothDevice.BOND_BONDED);
+            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+                mBondState.clearPinAttempts(address);
+            }
+        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+                mBondState.getAttempt(address) == 1) {
+            mBondState.addAutoPairingFailure(address);
+            pairingAttempt(address, result);
+        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+              mBondState.isAutoPairingAttemptsInProgress(address)) {
+            pairingAttempt(address, result);
+        } else {
+            setBondState(address, BluetoothDevice.BOND_NONE, result);
+            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+                mBondState.clearPinAttempts(address);
+            }
+        }
+    }
+
+    /*package*/ synchronized String getPendingOutgoingBonding() {
+        return mBondState.getPendingOutgoingBonding();
+    }
+
+    private void pairingAttempt(String address, int result) {
+        // This happens when our initial guess of "0000" as the pass key
+        // fails. Try to create the bond again and display the pin dialog
+        // to the user. Use back-off while posting the delayed
+        // message. The initial value is
+        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+        // reached, display an error to the user.
+        int attempt = mBondState.getAttempt(address);
+        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+            mBondState.clearPinAttempts(address);
+            setBondState(address, BluetoothDevice.BOND_NONE, result);
+            return;
+        }
+
+        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        message.obj = address;
+        boolean postResult =  mHandler.sendMessageDelayed(message,
+                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        if (!postResult) {
+            mBondState.clearPinAttempts(address);
+            setBondState(address,
+                    BluetoothDevice.BOND_NONE, result);
+            return;
+        }
+        mBondState.attempt(address);
     }
 
     /** local cache of bonding state.
@@ -1301,6 +1376,10 @@
         return mBondState.listInState(BluetoothDevice.BOND_BONDED);
     }
 
+    /*package*/ synchronized String[] listInState(int state) {
+      return mBondState.listInState(state);
+    }
+
     public synchronized int getBondState(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -1309,6 +1388,15 @@
         return mBondState.getBondState(address.toUpperCase());
     }
 
+    /*package*/ synchronized boolean setBondState(String address, int state) {
+        return setBondState(address, state, 0);
+    }
+
+    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
+        mBondState.setBondState(address.toUpperCase(), state);
+        return true;
+    }
+
     public synchronized boolean isBluetoothDock(String address) {
         SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
                 mContext.MODE_PRIVATE);