Bluetooth: Add support for HID Device Role

This patch adds the HID Device Role support in Bluetooth framework.
Also AIDL and callback related files for HID Device role are added
to provide interface for third party applications to communicate with
HID device Service.

Change-Id: Id03a362b7bcfa2e76056fa0197eaac12ce49b5a2
diff --git a/Android.mk b/Android.mk
index 77a6f87..fa0b579 100755
--- a/Android.mk
+++ b/Android.mk
@@ -113,6 +113,8 @@
 	core/java/android/bluetooth/IBluetoothMap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
 	core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
+	core/java/android/bluetooth/IBluetoothHidDevice.aidl \
+	core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
 	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8f0cd2..4c62dc4 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1422,6 +1422,9 @@
         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
             BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.HID_DEVICE) {
+            BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1493,6 +1496,10 @@
                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
                 headsetClient.close();
                 break;
+            case BluetoothProfile.HID_DEVICE:
+                BluetoothHidDevice hidd = (BluetoothHidDevice) proxy;
+                hidd.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index b8b8f5f..4995dda 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +18,6 @@
 
 package android.bluetooth;
 
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -26,209 +26,184 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
-
 /**
- * This class provides the public APIs to control the Bluetooth Input
- * Device Profile.
- *
- *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothInputDevice proxy object.
- *
- *<p>Each method is protected with its appropriate permission.
- *@hide
+ * @hide
  */
-public final class BluetoothInputDevice implements BluetoothProfile {
-    private static final String TAG = "BluetoothInputDevice";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+public final class BluetoothHidDevice implements BluetoothProfile {
 
-    /**
-     * Intent used to broadcast the change in connection state of the Input
-     * Device profile.
-     *
-     * <p>This intent will have 3 extras:
-     * <ul>
-     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
-     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
-     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
-     * </ul>
-     *
-     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
-     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
-     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
-     * receive.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    private static final String TAG = BluetoothHidDevice.class.getSimpleName();
+
     public static final String ACTION_CONNECTION_STATE_CHANGED =
-        "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
+        "android.bluetooth.hid.profile.action.CONNECTION_STATE_CHANGED";
 
     /**
-     * @hide
+     * Constants representing device subclass.
+     *
+     * @see #registerApp(String, String, String, byte, byte[],
+     *      BluetoothHidDeviceCallback)
      */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_PROTOCOL_MODE_CHANGED =
-        "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
+    public static final byte SUBCLASS1_NONE = (byte) 0x00;
+    public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
+    public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
+    public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
+
+    public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
+    public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
+    public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
+    public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
+    public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
+    public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05;
+    public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
 
     /**
-     * @hide
+     * Constants representing report types.
+     *
+     * @see BluetoothHidDeviceCallback#onGetReport(byte, byte, int)
+     * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
+     * @see BluetoothHidDeviceCallback#onIntrData(byte, byte[])
      */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_REPORT =
-        "android.bluetooth.input.profile.action.REPORT";
+    public static final byte REPORT_TYPE_INPUT = (byte) 1;
+    public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
+    public static final byte REPORT_TYPE_FEATURE = (byte) 3;
 
     /**
-     * @hide
+     * Constants representing error response for Set Report.
+     *
+     * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
      */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
-        "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
-
+    public static final byte ERROR_RSP_SUCCESS = (byte) 0;
+    public static final byte ERROR_RSP_NOT_READY = (byte) 1;
+    public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
+    public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
+    public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
+    public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
 
     /**
-     * Return codes for the connect and disconnect Bluez / Dbus calls.
-     * @hide
+     * Constants representing protocol mode used set by host. Default is always
+     * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+     *
+     * @see BluetoothHidDeviceCallback#onSetProtocol(byte)
      */
-    public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
-
-    /**
-     * @hide
-     */
-    public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
-
-    /**
-     * @hide
-     */
-    public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
-
-    /**
-     * @hide
-     */
-    public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
-
-    /**
-     * @hide
-     */
-    public static final int INPUT_OPERATION_SUCCESS = 5004;
-
-    /**
-     * @hide
-     */
-    public static final int PROTOCOL_REPORT_MODE = 0;
-
-    /**
-     * @hide
-     */
-    public static final int PROTOCOL_BOOT_MODE = 1;
-
-    /**
-     * @hide
-     */
-    public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
-
-    /*  int reportType, int reportType, int bufferSize */
-    /**
-     * @hide
-     */
-    public static final byte REPORT_TYPE_INPUT = 1;
-
-    /**
-     * @hide
-     */
-    public static final byte REPORT_TYPE_OUTPUT = 2;
-
-    /**
-     * @hide
-     */
-    public static final byte REPORT_TYPE_FEATURE = 3;
-
-    /**
-     * @hide
-     */
-    public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
-
-    /**
-     * @hide
-     */
-    public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_PROTOCOL_MODE = "android.bluetooth.BluetoothInputDevice.extra.PROTOCOL_MODE";
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_REPORT_TYPE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_TYPE";
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_REPORT_ID = "android.bluetooth.BluetoothInputDevice.extra.REPORT_ID";
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_REPORT_BUFFER_SIZE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_BUFFER_SIZE";
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_REPORT = "android.bluetooth.BluetoothInputDevice.extra.REPORT";
-
-    /**
-     * @hide
-     */
-    public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
+    public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
+    public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
 
     private Context mContext;
+
     private ServiceListener mServiceListener;
+
+    private IBluetoothHidDevice mService;
+
     private BluetoothAdapter mAdapter;
-    private IBluetoothInputDevice mService;
+
+    private static class BluetoothHidDeviceCallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
+
+        private BluetoothHidDeviceCallback mCallback;
+
+        public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+                BluetoothHidDeviceAppConfiguration config, boolean registered) {
+            mCallback.onAppStatusChanged(pluggedDevice, config, registered);
+        }
+
+        @Override
+        public void onConnectionStateChanged(BluetoothDevice device, int state) {
+            mCallback.onConnectionStateChanged(device, state);
+        }
+
+        @Override
+        public void onGetReport(byte type, byte id, int bufferSize) {
+            mCallback.onGetReport(type, id, bufferSize);
+        }
+
+        @Override
+        public void onSetReport(byte type, byte id, byte[] data) {
+            mCallback.onSetReport(type, id, data);
+        }
+
+        @Override
+        public void onSetProtocol(byte protocol) {
+            mCallback.onSetProtocol(protocol);
+        }
+
+        @Override
+        public void onIntrData(byte reportId, byte[] data) {
+            mCallback.onIntrData(reportId, data);
+        }
+
+        @Override
+        public void onVirtualCableUnplug() {
+            mCallback.onVirtualCableUnplug();
+        }
+    }
 
     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-            new IBluetoothStateChangeCallback.Stub() {
-                public void onBluetoothStateChange(boolean up) {
-                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                    if (!up) {
-                        if (VDBG) Log.d(TAG,"Unbinding service...");
-                        synchronized (mConnection) {
-                            try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
-                            } catch (Exception re) {
-                                Log.e(TAG,"",re);
-                            }
-                        }
-                    } else {
-                        synchronized (mConnection) {
-                            try {
-                                if (mService == null) {
-                                    if (VDBG) Log.d(TAG,"Binding service...");
-                                    doBind();
-                                }
-                            } catch (Exception re) {
-                                Log.e(TAG,"",re);
-                            }
+        new IBluetoothStateChangeCallback.Stub() {
+
+        public void onBluetoothStateChange(boolean up) {
+            Log.d(TAG, "onBluetoothStateChange: up=" + up);
+            synchronized (mConnection) {
+                if (!up) {
+                    Log.d(TAG,"Unbinding service...");
+                    if (mService != null) {
+                        mService = null;
+                        try {
+                            mContext.unbindService(mConnection);
+                        } catch (IllegalArgumentException e) {
+                            Log.e(TAG,"onBluetoothStateChange: could not unbind service:", e);
                         }
                     }
+                } else {
+                    try {
+                        if (mService == null) {
+                            Log.d(TAG,"Binding HID Device service...");
+                            doBind();
+                        }
+                    } catch (IllegalStateException e) {
+                        Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+                    } catch (SecurityException e) {
+                        Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+                    }
                 }
-        };
+            }
+        }
+    };
 
-    /**
-     * Create a BluetoothInputDevice proxy object for interacting with the local
-     * Bluetooth Service which handles the InputDevice profile
-     *
-     */
-    /*package*/ BluetoothInputDevice(Context context, ServiceListener l) {
+    private ServiceConnection mConnection = new ServiceConnection() {
+
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.d(TAG, "onServiceConnected()");
+
+            mService = IBluetoothHidDevice.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
+                    BluetoothHidDevice.this);
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            Log.d(TAG, "onServiceDisconnected()");
+
+            mService = null;
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+            }
+        }
+    };
+
+    BluetoothHidDevice(Context context, ServiceListener listener) {
+        Log.v(TAG, "BluetoothHidDevice");
+
         mContext = context;
-        mServiceListener = l;
+        mServiceListener = listener;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
 
         IBluetoothManager mgr = mAdapter.getBluetoothManager();
@@ -236,7 +211,7 @@
             try {
                 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
             } catch (RemoteException e) {
-                Log.e(TAG,"",e);
+                e.printStackTrace();
             }
         }
 
@@ -244,408 +219,283 @@
     }
 
     boolean doBind() {
-        Intent intent = new Intent(IBluetoothInputDevice.class.getName());
+        Intent intent = new Intent(IBluetoothHidDevice.class.getName());
         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
         intent.setComponent(comp);
         if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
+            Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
             return false;
         }
+        Log.d(TAG, "Bound to HID Device Service");
         return true;
     }
 
-    /*package*/ void close() {
-        if (VDBG) log("close()");
+    void close() {
+        Log.v(TAG, "close()");
+
         IBluetoothManager mgr = mAdapter.getBluetoothManager();
         if (mgr != null) {
             try {
                 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (Exception e) {
-                Log.e(TAG,"",e);
+            } catch (RemoteException e) {
+                e.printStackTrace();
             }
         }
 
         synchronized (mConnection) {
             if (mService != null) {
+                mService = null;
                 try {
-                    mService = null;
                     mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG,"",re);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"close: could not unbind HID Dev service: ", e);
                 }
            }
         }
+
         mServiceListener = null;
     }
 
-    /**
-     * Initiate connection to a profile of the remote bluetooth device.
-     *
-     * <p> The system supports connection to multiple input devices.
-     *
-     * <p> This API returns false in scenarios like the profile on the
-     * device is already connected or Bluetooth is not turned on.
-     * When this API returns true, it is guaranteed that
-     * connection state intent for the profile will be broadcasted with
-     * the state. Users can get the connection state of the profile
-     * from this intent.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
-     */
-    public boolean connect(BluetoothDevice device) {
-        if (DBG) log("connect(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.connect(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
-    }
-
-    /**
-     * Initiate disconnection from a profile
-     *
-     * <p> This API will return false in scenarios like the profile on the
-     * Bluetooth device is not in connected state etc. When this API returns,
-     * true, it is guaranteed that the connection state change
-     * intent will be broadcasted with the state. Users can get the
-     * disconnection state of the profile from this intent.
-     *
-     * <p> If the disconnection is initiated by a remote device, the state
-     * will transition from {@link #STATE_CONNECTED} to
-     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
-     * host (local) device the state will transition from
-     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
-     * state {@link #STATE_DISCONNECTED}. The transition to
-     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
-     * two scenarios.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
-     */
-    public boolean disconnect(BluetoothDevice device) {
-        if (DBG) log("disconnect(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.disconnect(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        if (VDBG) log("getConnectedDevices()");
-        if (mService != null && isEnabled()) {
-            try {
-                return mService.getConnectedDevices();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.v(TAG, "getConnectedDevices()");
+        return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        if (VDBG) log("getDevicesMatchingStates()");
-        if (mService != null && isEnabled()) {
-            try {
-                return mService.getDevicesMatchingConnectionStates(states);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
+        return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public int getConnectionState(BluetoothDevice device) {
-        if (VDBG) log("getState(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.getConnectionState(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return BluetoothProfile.STATE_DISCONNECTED;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return BluetoothProfile.STATE_DISCONNECTED;
+        Log.v(TAG, "getConnectionState(): device=" + device.getAddress());
+
+        return STATE_DISCONNECTED;
     }
 
     /**
-     * Set priority of the profile
+     * Registers application to be used for HID device. Connections to HID
+     * Device are only possible when application is registered. Only one
+     * application can be registered at time. When no longer used, application
+     * should be unregistered using
+     * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
      *
-     * <p> The device should already be paired.
-     *  Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
-     * @param device Paired bluetooth device
-     * @param priority
-     * @return true if priority is set, false on error
-     * @hide
+     * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of
+     *             HID Device SDP record.
+     * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of
+     *             Incoming QoS Settings.
+     * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of
+     *             Outgoing QoS Settings.
+     * @param callback {@link BluetoothHidDeviceCallback} object to which
+     *            callback messages will be sent.
+     * @return
      */
-    public boolean setPriority(BluetoothDevice device, int priority) {
-        if (DBG) log("setPriority(" + device + ", " + priority + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF &&
-                priority != BluetoothProfile.PRIORITY_ON) {
-              return false;
-            }
-            try {
-                return mService.setPriority(device, priority);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
-    }
+    public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
+            BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
+            BluetoothHidDeviceCallback callback) {
+        Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
+                + " callback=" + callback);
 
-    /**
-     * Get the priority of the profile.
-     *
-     * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Bluetooth device
-     * @return priority of the device
-     * @hide
-     */
-    public int getPriority(BluetoothDevice device) {
-        if (VDBG) log("getPriority(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.getPriority(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return BluetoothProfile.PRIORITY_OFF;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return BluetoothProfile.PRIORITY_OFF;
-    }
+        boolean result = false;
 
-    private final ServiceConnection mConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothInputDevice.Stub.asInterface(service);
-
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this);
-            }
-        }
-        public void onServiceDisconnected(ComponentName className) {
-            if (DBG) Log.d(TAG, "Proxy object disconnected");
-            mService = null;
-            if (mServiceListener != null) {
-                mServiceListener.onServiceDisconnected(BluetoothProfile.INPUT_DEVICE);
-            }
-        }
-    };
-
-    private boolean isEnabled() {
-       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
-       return false;
-    }
-
-    private boolean isValidDevice(BluetoothDevice device) {
-       if (device == null) return false;
-
-       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
-       return false;
-    }
-
-
-    /**
-     * Initiate virtual unplug for a HID input device.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
-     */
-    public boolean virtualUnplug(BluetoothDevice device) {
-        if (DBG) log("virtualUnplug(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.virtualUnplug(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
-            }
-        }
-
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
-
-    }
-
-    /**
-    * Send Get_Protocol_Mode command to the connected HID input device.
-    *
-    * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
-    *
-    * @param device Remote Bluetooth Device
-    * @return false on immediate error,
-    *true otherwise
-    * @hide
-    */
-    public boolean getProtocolMode(BluetoothDevice device) {
-        if (VDBG) log("getProtocolMode(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return mService.getProtocolMode(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (sdp == null || callback == null) {
             return false;
+        }
+
+        if (mService != null) {
+            try {
+                BluetoothHidDeviceAppConfiguration config =
+                    new BluetoothHidDeviceAppConfiguration();
+                BluetoothHidDeviceCallbackWrapper cbw =
+                    new BluetoothHidDeviceCallbackWrapper(callback);
+                result = mService.registerApp(config, sdp, inQos, outQos, cbw);
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return result;
     }
 
     /**
-     * Send Set_Protocol_Mode command to the connected HID input device.
+     * Unregisters application. Active connection will be disconnected and no
+     * new connections will be allowed until registered again using
+     * {@link #registerApp(String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+     * @param config {@link BluetoothHidDeviceAppConfiguration} object as
+     *            obtained from
+     *            {@link BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
+     *            BluetoothHidDeviceAppConfiguration, boolean)}
      *
-     * @param device Remote Bluetooth Device
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
+     * @return
      */
-    public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
-        if (DBG) log("setProtocolMode(" + device + ")");
-        if (mService != null && isEnabled() && isValidDevice(device)) {
+    public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
+        Log.v(TAG, "unregisterApp()");
+
+        boolean result = false;
+
+        if (mService != null) {
             try {
-                return mService.setProtocolMode(device, protocolMode);
+                result = mService.unregisterApp(config);
             } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
+                Log.e(TAG, e.toString());
             }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
+
+        return result;
     }
 
     /**
-     * Send Get_Report command to the connected HID input device.
+     * Sends report to remote host using interrupt channel.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @param reportType Report type
-     * @param reportId Report ID
-     * @param bufferSize Report receiving buffer size
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
+     * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id
+     *            are not defined in descriptor.
+     * @param data Report data, not including Report Id.
+     * @return
      */
-    public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
-        if (VDBG) log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId + "bufferSize=" + bufferSize);
-        if (mService != null && isEnabled() && isValidDevice(device)) {
+    public boolean sendReport(int id, byte[] data) {
+        Log.v(TAG, "sendReport(): id=" + id);
+
+        boolean result = false;
+
+        if (mService != null) {
             try {
-                return mService.getReport(device, reportType, reportId, bufferSize);
+                result = mService.sendReport(id, data);
             } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
+                Log.e(TAG, e.toString());
             }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
+
+        return result;
     }
 
     /**
-     * Send Set_Report command to the connected HID input device.
+     * Sends report to remote host as reply for GET_REPORT request from
+     * {@link BluetoothHidDeviceCallback#onGetReport(byte, byte, int)}.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @param reportType Report type
-     * @param report Report receiving buffer size
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
+     * @param type Report Type, as in request.
+     * @param id Report Id, as in request.
+     * @param data Report data, not including Report Id.
+     * @return
      */
-    public boolean setReport(BluetoothDevice device, byte reportType, String report) {
-        if (DBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
-        if (mService != null && isEnabled() && isValidDevice(device)) {
+    public boolean replyReport(byte type, byte id, byte[] data) {
+        Log.v(TAG, "replyReport(): type=" + type + " id=" + id);
+
+        boolean result = false;
+
+        if (mService != null) {
             try {
-                return mService.setReport(device, reportType, report);
+                result = mService.replyReport(type, id, data);
             } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
+                Log.e(TAG, e.toString());
             }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
+
+        return result;
     }
 
     /**
-     * Send Send_Data command to the connected HID input device.
+     * Sends error handshake message as reply for invalid SET_REPORT request
+     * from {@link BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])}.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
-     *
-     * @param device Remote Bluetooth Device
-     * @param data Data to send
-     * @return false on immediate error,
-     *               true otherwise
-     * @hide
+     * @param error Error to be sent for SET_REPORT via HANDSHAKE.
+     * @return
      */
-    public boolean sendData(BluetoothDevice device, String report) {
-        if (DBG) log("sendData(" + device + "), report=" + report);
-        if (mService != null && isEnabled() && isValidDevice(device)) {
+    public boolean reportError(byte error) {
+        Log.v(TAG, "reportError(): error = " + error);
+
+        boolean result = false;
+
+        if (mService != null) {
             try {
-                return mService.sendData(device, report);
+                result = mService.reportError(error);
             } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return false;
+                Log.e(TAG, e.toString());
             }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-        return false;
+
+        return result;
     }
-    private static void log(String msg) {
-      Log.d(TAG, msg);
+
+    /**
+     * Sends Virtual Cable Unplug to currently connected host.
+     *
+     * @return
+     */
+    public boolean unplug() {
+        Log.v(TAG, "unplug()");
+
+        boolean result = false;
+
+        if (mService != null) {
+            try {
+                result = mService.unplug();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return result;
+    }
+
+    /**
+     * Initiates connection to host which currently has Virtual Cable
+     * established with device.
+     *
+     * @return
+     */
+    public boolean connect() {
+        Log.v(TAG, "connect()");
+
+        boolean result = false;
+
+        if (mService != null) {
+            try {
+                result = mService.connect();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return result;
+    }
+
+    /**
+     * Disconnects from currently connected host.
+     *
+     * @return
+     */
+    public boolean disconnect() {
+        Log.v(TAG, "disconnect()");
+
+        boolean result = false;
+
+        if (mService != null) {
+            try {
+                result = mService.disconnect();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return result;
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
index bc9e54f..1af309c 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
@@ -1,4 +1,6 @@
 /*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +18,4 @@
 
 package android.bluetooth;
 
-parcelable BluetoothHealthAppConfiguration;
+parcelable BluetoothHidDeviceAppConfiguration;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
index 15a9101..9f3cd3c 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,152 +16,57 @@
  * limitations under the License.
  */
 
-
 package android.bluetooth;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
-/**
- * The Bluetooth Health Application Configuration that is used in conjunction with
- * the {@link BluetoothHealth} class. This class represents an application configuration
- * that the Bluetooth Health third party application will register to communicate with the
- * remote Bluetooth health device.
- *
- */
-public final class BluetoothHealthAppConfiguration implements Parcelable {
-    private final String mName;
-    private final int mDataType;
-    private final int mRole;
-    private final int mChannelType;
+import java.util.Random;
 
-    /**
-     * Constructor to register the SINK role
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = BluetoothHealth.SINK_ROLE;
-        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
+/** @hide */
+public final class BluetoothHidDeviceAppConfiguration implements Parcelable {
+    private final long mHash;
+
+    BluetoothHidDeviceAppConfiguration() {
+        Random rnd = new Random();
+        mHash = rnd.nextLong();
     }
 
-    /**
-     * Constructor to register the application configuration.
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @param role {@link BluetoothHealth#SOURCE_ROLE} or
-     *                     {@link BluetoothHealth#SINK_ROLE}
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
-        channelType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = role;
-        mChannelType = channelType;
+    BluetoothHidDeviceAppConfiguration(long hash) {
+        mHash = hash;
     }
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof BluetoothHealthAppConfiguration) {
-            BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-            // config.getName() can never be NULL
-            return mName.equals(config.getName()) &&
-                    mDataType == config.getDataType() &&
-                    mRole == config.getRole() &&
-                    mChannelType == config.getChannelType();
+        if (o instanceof BluetoothHidDeviceAppConfiguration) {
+            BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o;
+            return mHash == config.mHash;
         }
         return false;
     }
 
     @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + (mName != null ? mName.hashCode() : 0);
-        result = 31 * result + mDataType;
-        result = 31 * result + mRole;
-        result = 31 * result + mChannelType;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "BluetoothHealthAppConfiguration [mName = " + mName +
-            ",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
-            mChannelType + "]";
-    }
-
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Return the data type associated with this application configuration.
-     *
-     * @return dataType
-     */
-    public int getDataType() {
-        return mDataType;
-    }
+    public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR =
+        new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() {
 
-    /**
-     * Return the name of the application configuration.
-     *
-     * @return String name
-     */
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * Return the role associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#SOURCE_ROLE} or
-     *                         {@link BluetoothHealth#SINK_ROLE}
-     */
-    public int getRole() {
-        return mRole;
-    }
-
-    /**
-     * Return the channel type associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
-     * @hide
-     */
-    public int getChannelType() {
-        return mChannelType;
-    }
-
-    public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
-        new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
         @Override
-        public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
-            String name = in.readString();
-            int type = in.readInt();
-            int role = in.readInt();
-            int channelType = in.readInt();
-            return new BluetoothHealthAppConfiguration(name, type, role,
-                channelType);
+        public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) {
+            long hash = in.readLong();
+            return new BluetoothHidDeviceAppConfiguration(hash);
         }
 
         @Override
-        public BluetoothHealthAppConfiguration[] newArray(int size) {
-            return new BluetoothHealthAppConfiguration[size];
+        public BluetoothHidDeviceAppConfiguration[] newArray(int size) {
+            return new BluetoothHidDeviceAppConfiguration[size];
         }
     };
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeInt(mDataType);
-        out.writeInt(mRole);
-        out.writeInt(mChannelType);
+        out.writeLong(mHash);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
index bc9e54f..ae93235 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
@@ -1,4 +1,6 @@
 /*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +18,4 @@
 
 package android.bluetooth;
 
-parcelable BluetoothHealthAppConfiguration;
+parcelable BluetoothHidDeviceAppQosSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index 15a9101..a4044d9 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,152 +16,84 @@
  * limitations under the License.
  */
 
-
 package android.bluetooth;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
-/**
- * The Bluetooth Health Application Configuration that is used in conjunction with
- * the {@link BluetoothHealth} class. This class represents an application configuration
- * that the Bluetooth Health third party application will register to communicate with the
- * remote Bluetooth health device.
- *
- */
-public final class BluetoothHealthAppConfiguration implements Parcelable {
-    private final String mName;
-    private final int mDataType;
-    private final int mRole;
-    private final int mChannelType;
+import java.util.Random;
 
-    /**
-     * Constructor to register the SINK role
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = BluetoothHealth.SINK_ROLE;
-        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
-    }
+/** @hide */
+public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
 
-    /**
-     * Constructor to register the application configuration.
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @param role {@link BluetoothHealth#SOURCE_ROLE} or
-     *                     {@link BluetoothHealth#SINK_ROLE}
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
-        channelType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = role;
-        mChannelType = channelType;
+    final public int serviceType;
+    final public int tokenRate;
+    final public int tokenBucketSize;
+    final public int peakBandwidth;
+    final public int latency;
+    final public int delayVariation;
+
+    final static public int SERVICE_NO_TRAFFIC = 0x00;
+    final static public int SERVICE_BEST_EFFORT = 0x01;
+    final static public int SERVICE_GUARANTEED = 0x02;
+
+    final static public int MAX = (int) 0xffffffff;
+
+    public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
+            int peakBandwidth,
+            int latency, int delayVariation) {
+        this.serviceType = serviceType;
+        this.tokenRate = tokenRate;
+        this.tokenBucketSize = tokenBucketSize;
+        this.peakBandwidth = peakBandwidth;
+        this.latency = latency;
+        this.delayVariation = delayVariation;
     }
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof BluetoothHealthAppConfiguration) {
-            BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-            // config.getName() can never be NULL
-            return mName.equals(config.getName()) &&
-                    mDataType == config.getDataType() &&
-                    mRole == config.getRole() &&
-                    mChannelType == config.getChannelType();
+        if (o instanceof BluetoothHidDeviceAppQosSettings) {
+            BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
+            return false;
         }
         return false;
     }
 
     @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + (mName != null ? mName.hashCode() : 0);
-        result = 31 * result + mDataType;
-        result = 31 * result + mRole;
-        result = 31 * result + mChannelType;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "BluetoothHealthAppConfiguration [mName = " + mName +
-            ",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
-            mChannelType + "]";
-    }
-
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Return the data type associated with this application configuration.
-     *
-     * @return dataType
-     */
-    public int getDataType() {
-        return mDataType;
-    }
+    public static final Parcelable.Creator<BluetoothHidDeviceAppQosSettings> CREATOR =
+        new Parcelable.Creator<BluetoothHidDeviceAppQosSettings>() {
 
-    /**
-     * Return the name of the application configuration.
-     *
-     * @return String name
-     */
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * Return the role associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#SOURCE_ROLE} or
-     *                         {@link BluetoothHealth#SINK_ROLE}
-     */
-    public int getRole() {
-        return mRole;
-    }
-
-    /**
-     * Return the channel type associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
-     * @hide
-     */
-    public int getChannelType() {
-        return mChannelType;
-    }
-
-    public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
-        new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
         @Override
-        public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
-            String name = in.readString();
-            int type = in.readInt();
-            int role = in.readInt();
-            int channelType = in.readInt();
-            return new BluetoothHealthAppConfiguration(name, type, role,
-                channelType);
+        public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) {
+
+            return new BluetoothHidDeviceAppQosSettings(in.readInt(), in.readInt(), in.readInt(),
+                    in.readInt(),
+                    in.readInt(), in.readInt());
         }
 
         @Override
-        public BluetoothHealthAppConfiguration[] newArray(int size) {
-            return new BluetoothHealthAppConfiguration[size];
+        public BluetoothHidDeviceAppQosSettings[] newArray(int size) {
+            return new BluetoothHidDeviceAppQosSettings[size];
         }
     };
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeInt(mDataType);
-        out.writeInt(mRole);
-        out.writeInt(mChannelType);
+        out.writeInt(serviceType);
+        out.writeInt(tokenRate);
+        out.writeInt(tokenBucketSize);
+        out.writeInt(peakBandwidth);
+        out.writeInt(latency);
+        out.writeInt(delayVariation);
+    }
+
+    public int[] toArray() {
+        return new int[] {
+                serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+        };
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
index bc9e54f..38ac1ec 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
@@ -1,4 +1,6 @@
 /*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +18,4 @@
 
 package android.bluetooth;
 
-parcelable BluetoothHealthAppConfiguration;
+parcelable BluetoothHidDeviceAppSdpSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 15a9101..db88f0d 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,152 +16,67 @@
  * limitations under the License.
  */
 
-
 package android.bluetooth;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
-/**
- * The Bluetooth Health Application Configuration that is used in conjunction with
- * the {@link BluetoothHealth} class. This class represents an application configuration
- * that the Bluetooth Health third party application will register to communicate with the
- * remote Bluetooth health device.
- *
- */
-public final class BluetoothHealthAppConfiguration implements Parcelable {
-    private final String mName;
-    private final int mDataType;
-    private final int mRole;
-    private final int mChannelType;
+import java.util.Random;
 
-    /**
-     * Constructor to register the SINK role
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = BluetoothHealth.SINK_ROLE;
-        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
-    }
+/** @hide */
+public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
 
-    /**
-     * Constructor to register the application configuration.
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @param role {@link BluetoothHealth#SOURCE_ROLE} or
-     *                     {@link BluetoothHealth#SINK_ROLE}
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
-        channelType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = role;
-        mChannelType = channelType;
+    final public String name;
+    final public String description;
+    final public String provider;
+    final public byte subclass;
+    final public byte[] descriptors;
+
+    public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
+            byte subclass, byte[] descriptors) {
+        this.name = name;
+        this.description = description;
+        this.provider = provider;
+        this.subclass = subclass;
+        this.descriptors = descriptors.clone();
     }
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof BluetoothHealthAppConfiguration) {
-            BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-            // config.getName() can never be NULL
-            return mName.equals(config.getName()) &&
-                    mDataType == config.getDataType() &&
-                    mRole == config.getRole() &&
-                    mChannelType == config.getChannelType();
+        if (o instanceof BluetoothHidDeviceAppSdpSettings) {
+            BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
+            return false;
         }
         return false;
     }
 
     @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + (mName != null ? mName.hashCode() : 0);
-        result = 31 * result + mDataType;
-        result = 31 * result + mRole;
-        result = 31 * result + mChannelType;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "BluetoothHealthAppConfiguration [mName = " + mName +
-            ",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
-            mChannelType + "]";
-    }
-
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Return the data type associated with this application configuration.
-     *
-     * @return dataType
-     */
-    public int getDataType() {
-        return mDataType;
-    }
+    public static final Parcelable.Creator<BluetoothHidDeviceAppSdpSettings> CREATOR =
+        new Parcelable.Creator<BluetoothHidDeviceAppSdpSettings>() {
 
-    /**
-     * Return the name of the application configuration.
-     *
-     * @return String name
-     */
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * Return the role associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#SOURCE_ROLE} or
-     *                         {@link BluetoothHealth#SINK_ROLE}
-     */
-    public int getRole() {
-        return mRole;
-    }
-
-    /**
-     * Return the channel type associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
-     *                         {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
-     * @hide
-     */
-    public int getChannelType() {
-        return mChannelType;
-    }
-
-    public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
-        new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
         @Override
-        public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
-            String name = in.readString();
-            int type = in.readInt();
-            int role = in.readInt();
-            int channelType = in.readInt();
-            return new BluetoothHealthAppConfiguration(name, type, role,
-                channelType);
+        public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) {
+
+            return new BluetoothHidDeviceAppSdpSettings(in.readString(), in.readString(),
+                    in.readString(), in.readByte(), in.createByteArray());
         }
 
         @Override
-        public BluetoothHealthAppConfiguration[] newArray(int size) {
-            return new BluetoothHealthAppConfiguration[size];
+        public BluetoothHidDeviceAppSdpSettings[] newArray(int size) {
+            return new BluetoothHidDeviceAppSdpSettings[size];
         }
     };
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeInt(mDataType);
-        out.writeInt(mRole);
-        out.writeInt(mChannelType);
+        out.writeString(name);
+        out.writeString(description);
+        out.writeString(provider);
+        out.writeByte(subclass);
+        out.writeByteArray(descriptors);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index baf2ade..cc60833 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,55 +16,113 @@
  * limitations under the License.
  */
 
-
 package android.bluetooth;
 
-import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
-/**
- * This abstract class is used to implement {@link BluetoothHealth} callbacks.
- */
-public abstract class BluetoothHealthCallback {
-    private static final String TAG = "BluetoothHealthCallback";
+/** @hide */
+public abstract class BluetoothHidDeviceCallback {
+
+    private static final String TAG = BluetoothHidDeviceCallback.class.getSimpleName();
 
     /**
-     * Callback to inform change in registration state of the health
-     * application.
-     * <p> This callback is called on the binder thread (not on the UI thread)
+     * Callback called when application registration state changes. Usually it's
+     * called due to either
+     * {@link BluetoothHidDevice#registerApp(String, String, String, byte, byte[],
+     * BluetoothHidDeviceCallback)}
+     * or
+     * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+     * , but can be also unsolicited in case e.g. Bluetooth was turned off in
+     * which case application is unregistered automatically.
      *
-     * @param config Bluetooth Health app configuration
-     * @param status Success or failure of the registration or unregistration
-     *            calls. Can be one of
-     *            {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or
-     *            {@link BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
-     *            {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} or
-     *            {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+     * @param pluggedDevice {@link BluetoothDevice} object which represents host
+     *            that currently has Virtual Cable established with device. Only
+     *            valid when application is registered, can be <code>null</code>
+     *            .
+     * @param config {@link BluetoothHidDeviceAppConfiguration} object which
+     *            represents token required to unregister application using
+     *            {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+     *            .
+     * @param registered <code>true</code> if application is registered,
+     *            <code>false</code> otherwise.
      */
-    public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
-            int status) {
-        Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
+    public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+                                    BluetoothHidDeviceAppConfiguration config, boolean registered) {
+        Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + (pluggedDevice == null ?
+            null : pluggedDevice.toString()) + " registered=" + registered);
     }
 
     /**
-     * Callback to inform change in channel state.
-     * <p> Its the responsibility of the implementor of this callback to close the
-     * parcel file descriptor when done. This callback is called on the Binder
-     * thread (not the UI thread)
+     * Callback called when connection state with remote host was changed.
+     * Application can assume than Virtual Cable is established when called with
+     * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>.
      *
-     * @param config The Health app configutation
-     * @param device The Bluetooth Device
-     * @param prevState The previous state of the channel
-     * @param newState The new state of the channel.
-     * @param fd The Parcel File Descriptor when the channel state is connected.
-     * @param channelId The id associated with the channel. This id will be used
-     *            in future calls like when disconnecting the channel.
+     * @param device {@link BluetoothDevice} object representing host device
+     *            which connection state was changed.
+     * @param state Connection state as defined in {@link BluetoothProfile}.
      */
-    public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
-            BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
-            int channelId) {
-        Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device +
-              "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd +
-              "ChannelId:" + channelId);
+    public void onConnectionStateChanged(BluetoothDevice device, int state) {
+        Log.d(TAG, "onConnectionStateChanged: device=" + device.toString() + " state=" + state);
+    }
+
+    /**
+     * Callback called when GET_REPORT is received from remote host. Should be
+     * replied by application using
+     * {@link BluetoothHidDevice#replyReport(byte, byte, byte[])}.
+     *
+     * @param type Requested Report Type.
+     * @param id Requested Report Id, can be 0 if no Report Id are defined in
+     *            descriptor.
+     * @param bufferSize Requested buffer size, application shall respond with
+     *            at least given number of bytes.
+     */
+    public void onGetReport(byte type, byte id, int bufferSize) {
+        Log.d(TAG, "onGetReport: type=" + type + " id=" + id + " bufferSize=" + bufferSize);
+    }
+
+    /**
+     * Callback called when SET_REPORT is received from remote host. In case
+     * received data are invalid, application shall respond with
+     * {@link BluetoothHidDevice#reportError()}.
+     *
+     * @param type Report Type.
+     * @param id Report Id.
+     * @param data Report data.
+     */
+    public void onSetReport(byte type, byte id, byte[] data) {
+        Log.d(TAG, "onSetReport: type=" + type + " id=" + id);
+    }
+
+    /**
+     * Callback called when SET_PROTOCOL is received from remote host.
+     * Application shall use this information to send only reports valid for
+     * given protocol mode. By default,
+     * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+     *
+     * @param protocol Protocol Mode.
+     */
+    public void onSetProtocol(byte protocol) {
+        Log.d(TAG, "onSetProtocol: protocol=" + protocol);
+    }
+
+    /**
+     * Callback called when report data is received over interrupt channel.
+     * Report Type is assumed to be
+     * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+     *
+     * @param reportId Report Id.
+     * @param data Report data.
+     */
+    public void onIntrData(byte reportId, byte[] data) {
+        Log.d(TAG, "onIntrData: reportId=" + reportId);
+    }
+
+    /**
+     * Callback called when Virtual Cable is removed. This can be either due to
+     * {@link BluetoothHidDevice#unplug()} or request from remote side. After
+     * this callback is received connection will be disconnected automatically.
+     */
+    public void onVirtualCableUnplug() {
+        Log.d(TAG, "onVirtualCableUnplug");
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index e998a46..80c5aa4 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -122,11 +122,11 @@
     public static final int HEADSET_CLIENT = 16;
 
     /**
-     * DUN
+     * HID device
      * @hide
      */
+    static public final int HID_DEVICE = 17;
 
-    public static final int DUN = 21;
     /**
      * SAP
      * @hide
@@ -134,6 +134,13 @@
     public static final int SAP = 20;
 
     /**
+     * DUN
+     * @hide
+     */
+
+    public static final int DUN = 21;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/bluetooth/IBluetoothHidDevice.aidl b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
index 1ebb9ca..60358c5 100644
--- a/core/java/android/bluetooth/IBluetoothHidDevice.aidl
+++ b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,43 +19,21 @@
 package android.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
+import android.bluetooth.IBluetoothHidDeviceCallback;
+import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
+import android.bluetooth.BluetoothHidDeviceAppQosSettings;
 
-/**
- * API for Bluetooth HID service
- *
- * {@hide}
- */
-interface IBluetoothInputDevice {
-    // Public API
-    boolean connect(in BluetoothDevice device);
-    boolean disconnect(in BluetoothDevice device);
-    List<BluetoothDevice> getConnectedDevices();
-    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
-    int getConnectionState(in BluetoothDevice device);
-    boolean setPriority(in BluetoothDevice device, int priority);
-    int getPriority(in BluetoothDevice device);
-    /**
-    * @hide
-    */
-    boolean getProtocolMode(in BluetoothDevice device);
-    /**
-    * @hide
-    */
-    boolean virtualUnplug(in BluetoothDevice device);
-    /**
-    * @hide
-    */
-    boolean setProtocolMode(in BluetoothDevice device, int protocolMode);
-    /**
-    * @hide
-    */
-    boolean getReport(in BluetoothDevice device, byte reportType, byte reportId, int bufferSize);
-    /**
-    * @hide
-    */
-    boolean setReport(in BluetoothDevice device, byte reportType, String report);
-    /**
-    * @hide
-    */
-    boolean sendData(in BluetoothDevice device, String report);
+/** @hide */
+interface IBluetoothHidDevice {
+    boolean registerApp(in BluetoothHidDeviceAppConfiguration config,
+            in BluetoothHidDeviceAppSdpSettings sdp, in BluetoothHidDeviceAppQosSettings inQos,
+            in BluetoothHidDeviceAppQosSettings outQos, in IBluetoothHidDeviceCallback callback);
+    boolean unregisterApp(in BluetoothHidDeviceAppConfiguration config);
+    boolean sendReport(in int id, in byte[] data);
+    boolean replyReport(in byte type, in byte id, in byte[] data);
+    boolean reportError(byte error);
+    boolean unplug();
+    boolean connect();
+    boolean disconnect();
 }
diff --git a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
index 0ace9fe..7c71a17 100644
--- a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
@@ -1,11 +1,13 @@
 /*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
  * Copyright (C) 2011, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,16 +19,15 @@
 package android.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHealthAppConfiguration;
-import android.os.ParcelFileDescriptor;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
 
-/**
- *@hide
- */
-interface IBluetoothHealthCallback
-{
-    void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
-    void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
-        in BluetoothDevice device, int prevState, int newState, in
-        ParcelFileDescriptor fd, int id);
+/** @hide */
+interface IBluetoothHidDeviceCallback {
+   void onAppStatusChanged(in BluetoothDevice device, in BluetoothHidDeviceAppConfiguration config, boolean registered);
+   void onConnectionStateChanged(in BluetoothDevice device, in int state);
+   void onGetReport(in byte type, in byte id, in int bufferSize);
+   void onSetReport(in byte type, in byte id, in byte[] data);
+   void onSetProtocol(in byte protocol);
+   void onIntrData(in byte reportId, in byte[] data);
+   void onVirtualCableUnplug();
 }