Allow enabling Bluetooth without auto-connecting.

This is a feature used for NFC-to-Bluetooth handover:
we want to enable BT for file transfer, and disconnect
it when we're done. During this period we don't want
to auto-connect other devices - it should be transparent
to the user that Bluetooth is used. Also, don't allow
A2DP/HSP incoming connections.

Change-Id: I0a03e8084c439b1271b6a80f4d9da5aacfe19c45
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 600ce6f..8e3df47 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1232,6 +1232,18 @@
     }
 
     /**
+     * Enable the Bluetooth Adapter, but don't auto-connect devices
+     * and don't persist state. Only for use by system applications.
+     * @hide
+     */
+    public boolean enableNoAutoConnect() {
+        try {
+            return mService.enableNoAutoConnect();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
      * Enable control of the Bluetooth Adapter for a single application.
      *
      * <p>Some applications need to use Bluetooth for short periods of time to
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index deea2b8..6075363 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -34,6 +34,7 @@
     boolean isEnabled();
     int getBluetoothState();
     boolean enable();
+    boolean enableNoAutoConnect();
     boolean disable(boolean persistSetting);
 
     String getAddress();
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 36c0189..7a97455 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -165,6 +165,8 @@
     private static String mDockAddress;
     private String mDockPin;
 
+    private boolean mAllowConnect = true;
+
     private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
     private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
     private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
@@ -472,7 +474,7 @@
 
     /** Bring up BT and persist BT on in settings */
     public boolean enable() {
-        return enable(true);
+        return enable(true, true);
     }
 
     /**
@@ -480,9 +482,11 @@
      * This turns on/off the underlying hardware.
      *
      * @param saveSetting If true, persist the new state of BT in settings
+     * @param allowConnect If true, auto-connects device when BT is turned on
+     *                     and allows incoming A2DP/HSP connections
      * @return True on success (so far)
      */
-    public synchronized boolean enable(boolean saveSetting) {
+    public synchronized boolean enable(boolean saveSetting, boolean allowConnect) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
 
@@ -490,11 +494,29 @@
         if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
             return false;
         }
+        mAllowConnect = allowConnect;
         mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
         return true;
     }
 
     /**
+     * Enable this Bluetooth device, asynchronously, but does not
+     * auto-connect devices. In this state the Bluetooth adapter
+     * also does not allow incoming A2DP/HSP connections (that
+     * must go through this service), but does allow communication
+     * on RFCOMM sockets implemented outside of this service (ie BTOPP).
+     * This method is used to temporarily enable Bluetooth
+     * for data transfer, without changing
+     *
+     * This turns on/off the underlying hardware.
+     *
+     * @return True on success (so far)
+     */
+    public boolean enableNoAutoConnect() {
+        return enable(false, false);
+    }
+
+    /**
      * Turn on Bluetooth Module, Load firmware, and do all the preparation
      * needed to get the Bluetooth Module ready but keep it not discoverable
      * and not connectable.
@@ -2441,6 +2463,13 @@
     }
 
     private void autoConnect() {
+        synchronized (this) {
+            if (!mAllowConnect) {
+                Log.d(TAG, "Not auto-connecting devices because of temporary BT on state.");
+                return;
+            }
+        }
+
         String[] bonds = getKnownDevices();
         if (bonds == null) {
             return;
@@ -2457,6 +2486,12 @@
     }
 
     public boolean notifyIncomingConnection(String address, boolean rejected) {
+        synchronized (this) {
+            if (!mAllowConnect) {
+                Log.d(TAG, "Not allowing incoming connection because of temporary BT on state.");
+                return false;
+            }
+        }
         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
         if (state != null) {
             Message msg = new Message();
@@ -2478,6 +2513,13 @@
     }
 
     /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
+        synchronized (this) {
+            if (!mAllowConnect) {
+                Log.d(TAG, "Not allowing a2dp connection because of temporary BT on state.");
+                return false;
+            }
+        }
+
        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
        if (state != null) {
            Message msg = new Message();