Add support for Car Dock.

Dr No: Eastham
Bug: 2133530
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 6cb9770..cf9c58f 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -624,6 +624,14 @@
         return false;
     }
 
+    /** @hide */
+    public boolean isBluetoothDock() {
+        try {
+            return sService.isBluetoothDock(mAddress);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
     /**
      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
      * outgoing connection to this remote device on given channel.
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 7e752af..0868779 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -64,6 +64,7 @@
 
     boolean setTrust(in String address, in boolean value);
     boolean getTrustState(in String address);
+    boolean isBluetoothDock(in String address);
 
     int addRfcommServiceRecord(in String serviceName, in ParcelUuid uuid, int channel, IBinder b);
     void removeServiceRecord(int handle);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index cb3b6ee..e960491 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -492,6 +492,14 @@
                 mBluetoothService.getBondState().getPendingOutgoingBonding();
         if (address.equals(pendingOutgoingAddress)) {
             // we initiated the bonding
+
+            // Check if its a dock
+            if (mBluetoothService.isBluetoothDock(address)) {
+                String pin = mBluetoothService.getDockPin();
+                mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes(pin));
+                return;
+            }
+
             BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
 
             // try 0000 once if the device looks dumb
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 765d510..1b117c7 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -32,16 +32,16 @@
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetooth;
 import android.bluetooth.IBluetoothCallback;
-import android.os.ParcelUuid;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Binder;
-import android.os.IBinder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemService;
@@ -50,7 +50,13 @@
 
 import com.android.internal.app.IBatteryStats;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
@@ -58,6 +64,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Random;
 
 public class BluetoothService extends IBluetooth.Stub {
     private static final String TAG = "BluetoothService";
@@ -79,6 +86,9 @@
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
 
+    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
+    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
+
     private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
     private static final int MESSAGE_FINISH_DISABLE = 2;
     private static final int MESSAGE_UUID_INTENT = 3;
@@ -104,6 +114,9 @@
 
     private final HashMap<Integer, Integer> mServiceRecordToPid;
 
+    private static String mDockAddress;
+    private String mDockPin;
+
     private static class RemoteService {
         public String address;
         public ParcelUuid uuid;
@@ -151,6 +164,96 @@
         mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
         mServiceRecordToPid = new HashMap<Integer, Integer>();
         registerForAirplaneMode();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DOCK_EVENT);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null) {
+                String action = intent.getAction();
+
+                if (Intent.ACTION_DOCK_EVENT.equals(action)) {
+                    int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                            Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                    if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
+                    if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                        mDockAddress = null;
+                        mDockPin = null;
+                    }
+                }
+            }
+        }
+    };
+
+     public static synchronized String readDockBluetoothAddress() {
+        if (mDockAddress != null) return mDockAddress;
+
+        BufferedInputStream file = null;
+        String dockAddress;
+        try {
+            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
+            byte[] address = new byte[17];
+            file.read(address);
+            dockAddress = new String(address);
+            dockAddress = dockAddress.toUpperCase();
+            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
+                mDockAddress = dockAddress;
+                return mDockAddress;
+            } else {
+                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
+            }
+        } catch (FileNotFoundException e) {
+            log("FileNotFoundException while trying to read dock address");
+        } catch (IOException e) {
+            log("IOException while trying to read dock address");
+        } finally {
+            if (file != null) {
+                try {
+                    file.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        mDockAddress = null;
+        return null;
+    }
+
+    private synchronized boolean writeDockPin() {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
+
+            // Generate a random 4 digit pin between 0000 and 9999
+            // This is not truly random but good enough for our purposes.
+            int pin = (int) Math.floor(Math.random() * 10000);
+
+            mDockPin = String.format("%04d", pin);
+            out.write(mDockPin);
+            return true;
+        } catch (FileNotFoundException e) {
+            log("FileNotFoundException while trying to write dock pairing pin");
+        } catch (IOException e) {
+            log("IOException while while trying to write dock pairing pin");
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        mDockPin = null;
+        return false;
+    }
+
+    /*package*/ synchronized String getDockPin() {
+        return mDockPin;
     }
 
     public synchronized void initAfterRegistration() {
@@ -922,6 +1025,13 @@
             return false;
         }
 
+        if (address.equals(mDockAddress)) {
+            if (!writeDockPin()) {
+                log("Error while writing Pin for the dock");
+                return false;
+            }
+        }
+
         if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
             return false;
         }
@@ -975,6 +1085,11 @@
         return mBondState.getBondState(address.toUpperCase());
     }
 
+    public synchronized boolean isBluetoothDock(String address) {
+        if (address.equals(mDockAddress)) return true;
+        return false;
+    }
+
     /*package*/ boolean isRemoteDeviceInCache(String address) {
         return (mDeviceProperties.get(address) != null);
     }
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index c2b1b96..2fff54c 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -18,6 +18,8 @@
 
 import android.app.Activity;
 import android.app.KeyguardManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -27,12 +29,13 @@
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.provider.Settings;
+import android.server.BluetoothService;
 import android.util.Log;
 
 import com.android.internal.widget.LockPatternUtils;
 
-import java.io.FileReader;
 import java.io.FileNotFoundException;
+import java.io.FileReader;
 
 /**
  * <p>DockObserver monitors for a docking station.
@@ -65,7 +68,7 @@
             if (getResultCode() != Activity.RESULT_OK) {
                 return;
             }
-            
+
             // Launch a dock activity
             String category;
             switch (mDockState) {
@@ -177,7 +180,13 @@
                 // Pack up the values and broadcast them to everyone
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-                
+
+                // Check if this is Bluetooth Dock
+                String address = BluetoothService.readDockBluetoothAddress();
+                if (address != null)
+                    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
+                            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
+
                 // Send the ordered broadcast; the result receiver will receive after all
                 // broadcasts have been sent. If any broadcast receiver changes the result
                 // code from the initial value of RESULT_OK, then the result receiver will