Implement  Profile Auto connection logic

Implement  Profile Auto connection logic  (moved from Settings App )in  Bluetooth APK
 to avoid Auto connection not happening if the Settings App is not running
As part of this implementation following features are implemented
1.	 Auto connection initiation during BT on OFF
2.	Profile Auto connection priority management
3.	Connecting Missing profile logic
4.	Initialize Profile Priorities on Bond State Change

Change-Id: I12b7c190e28f043b4b008c9b48ac7e13aaf178e6
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 4835890..4441f4b 100755
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -25,6 +25,7 @@
     private static final String TAG="A2dpService";
 
     private A2dpStateMachine mStateMachine;
+    private static A2dpService sAd2dpService;
 
     protected String getName() {
         return TAG;
@@ -37,6 +38,7 @@
     protected boolean start() {
         mStateMachine = new A2dpStateMachine(this,this);
         mStateMachine.start();
+        setA2dpService(this);
         return true;
     }
 
@@ -50,11 +52,47 @@
             mStateMachine.cleanup();
             mStateMachine=null;
         }
+        clearA2dpService();
         return true;
     }
 
     //API Methods
-    boolean connect(BluetoothDevice device) {
+
+    public static synchronized A2dpService getA2dpService(){
+        if (sAd2dpService != null && sAd2dpService.isAvailable()) {
+            if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
+            return sAd2dpService;
+        }
+        if (DBG)  {
+            if (sAd2dpService == null) {
+                Log.d(TAG, "getA2dpService(): service is NULL");
+            } else if (!(sAd2dpService.isAvailable())) {
+                Log.d(TAG,"getA2dpService(): service is not available");
+            }
+        }
+        return null;
+    }
+
+    private static synchronized void setA2dpService(A2dpService instance) {
+        if (instance != null && instance.isAvailable()) {
+            if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
+            sAd2dpService = instance;
+        } else {
+            if (DBG)  {
+                if (sAd2dpService == null) {
+                    Log.d(TAG, "setA2dpService(): service not available");
+                } else if (!sAd2dpService.isAvailable()) {
+                    Log.d(TAG,"setA2dpService(): service is cleaning up");
+                }
+            }
+        }
+    }
+
+    private static synchronized void clearA2dpService() {
+        sAd2dpService = null;
+    }
+
+    public boolean connect(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH ADMIN permission");
 
@@ -85,7 +123,7 @@
         return true;
     }
 
-    List<BluetoothDevice> getConnectedDevices() {
+    public List<BluetoothDevice> getConnectedDevices() {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return mStateMachine.getConnectedDevices();
     }
@@ -100,7 +138,7 @@
         return mStateMachine.getConnectionState(device);
     }
 
-    boolean setPriority(BluetoothDevice device, int priority) {
+    public boolean setPriority(BluetoothDevice device, int priority) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         Settings.Secure.putInt(getContentResolver(),
@@ -110,7 +148,7 @@
         return true;
     }
 
-    int getPriority(BluetoothDevice device) {
+    public int getPriority(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         int priority = Settings.Secure.getInt(getContentResolver(),
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
old mode 100644
new mode 100755
index 8d42512..c742fd4
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -231,7 +231,11 @@
                     Log.i(TAG,"Incoming A2DP rejected");
                     disconnectA2dpNative(getByteAddress(device));
                     // the other profile connection should be initiated
-                    broadcastConnectOtherProfilesIntent(device);
+                    AdapterService adapterService = AdapterService.getAdapterService();
+                    if (adapterService != null) {
+                        adapterService.connectOtherProfile(device,
+                                                           AdapterService.PROFILE_CONN_REJECTED);
+                    }
                 }
                 break;
             case CONNECTION_STATE_CONNECTED:
@@ -252,7 +256,11 @@
                     Log.i(TAG,"Incoming A2DP rejected");
                     disconnectA2dpNative(getByteAddress(device));
                     // the other profile connection should be initiated
-                    broadcastConnectOtherProfilesIntent(device);
+                    AdapterService adapterService = AdapterService.getAdapterService();
+                    if (adapterService != null) {
+                        adapterService.connectOtherProfile(device,
+                                                           AdapterService.PROFILE_CONN_REJECTED);
+                    }
                 }
                 break;
             case CONNECTION_STATE_DISCONNECTING:
@@ -645,14 +653,6 @@
         return deviceList;
     }
 
-    private void broadcastConnectOtherProfilesIntent(BluetoothDevice device) {
-        // send other profile connect intent
-        if (DBG) log("Other Profile Connect intent sent " + device);
-
-        Intent intent = new Intent(BluetoothProfile.ACTION_CONNECT_OTHER_PROFILES);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        mContext.sendBroadcast(intent, A2dpService.BLUETOOTH_PERM);
-    }
 
     // This method does not check for error conditon (newState == prevState)
     private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) {
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 1e56129..7e0bbd1 100755
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -50,6 +50,7 @@
 import java.util.Map;
 import java.util.Iterator;
 import java.util.Map.Entry;
+import java.util.List;
 import android.content.pm.PackageManager;
 import android.os.ServiceManager;
 
@@ -63,6 +64,8 @@
     public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
     public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
     public static final String EXTRA_ACTION="action";
+    public static final int PROFILE_CONN_CONNECTED  = 1;
+    public static final int PROFILE_CONN_REJECTED  = 2;
 
     static final String BLUETOOTH_ADMIN_PERM =
         android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -143,6 +146,12 @@
     }
 
     private void processProfileStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
+        if (((profileId == BluetoothProfile.A2DP) ||(profileId == BluetoothProfile.HEADSET)) &&
+            (newState == BluetoothProfile.STATE_CONNECTED)){
+            if (DBG) debugLog( "Profile connected. Schedule missing profile connection if any");
+            connectOtherProfile(device, PROFILE_CONN_CONNECTED);
+            setProfileAutoConnectionPriority(device, profileId);
+        }
         IBluetooth.Stub binder = mBinder;
         if (binder != null) {
             try {
@@ -379,8 +388,10 @@
 
     private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
     private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
+    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 30;
     private static final int MESSAGE_SHUTDOWN= 100;
     private static final int SHUTDOWN_TIMEOUT=2000;
+    private static final int CONNECT_OTHER_PROFILES_TIMEOUT= 6000;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -403,6 +414,11 @@
                     processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
                 }
                     break;
+                case MESSAGE_CONNECT_OTHER_PROFILES: {
+                    if (DBG) debugLog( "MESSAGE_CONNECT_OTHER_PROFILES");
+                    processConnectOtherProfiles((BluetoothDevice) msg.obj,msg.arg1);
+                }
+                    break;
             }
         }
     };
@@ -713,8 +729,13 @@
 
      int getState() {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
-        return mAdapterProperties.getState();
+        if (mAdapterProperties == null){
+            return  BluetoothAdapter.STATE_OFF;
+        }
+        else {
+            debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
+            return mAdapterProperties.getState();
+        }
     }
 
      boolean enable() {
@@ -836,6 +857,101 @@
         return true;
     }
 
+     public void autoConnect(){
+        if (getState() != BluetoothAdapter.STATE_ON){
+             errorLog("BT is not ON. Exiting autoConnect");
+             return;
+         }
+         autoConnectHeadset();
+         autoConnectA2dp();
+    }
+
+     private void autoConnectHeadset(){
+        HeadsetService  hsService = HeadsetService.getHeadsetService();
+
+        BluetoothDevice bondedDevices[] = getBondedDevices();
+        if ((bondedDevices == null) ||(hsService == null)) {
+            return;
+        }
+        for (BluetoothDevice device : bondedDevices) {
+            if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
+                Log.d(TAG,"Auto Connecting Headset Profile with device " + device.toString());
+                hsService.connect(device);
+                }
+        }
+    }
+
+     private void autoConnectA2dp(){
+        A2dpService a2dpSservice = A2dpService.getA2dpService();
+        BluetoothDevice bondedDevices[] = getBondedDevices();
+        if ((bondedDevices == null) ||(a2dpSservice == null)) {
+            return;
+        }
+        for (BluetoothDevice device : bondedDevices) {
+            if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
+                Log.d(TAG,"Auto Connecting A2DP Profile with device " + device.toString());
+                a2dpSservice.connect(device);
+                }
+        }
+    }
+
+     public void connectOtherProfile(BluetoothDevice device, int firstProfileStatus){
+        if (mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false){
+            Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES);
+            m.obj = device;
+            m.arg1 = (int)firstProfileStatus;
+            mHandler.sendMessageDelayed(m,CONNECT_OTHER_PROFILES_TIMEOUT);
+        }
+    }
+
+     private void processConnectOtherProfiles (BluetoothDevice device, int firstProfileStatus){
+        if (getState()!= BluetoothAdapter.STATE_ON){
+            return;
+        }
+        HeadsetService  hsService = HeadsetService.getHeadsetService();
+        A2dpService a2dpService = A2dpService.getA2dpService();
+        // if any of the profile service is  null, second profile connection not required
+        if ((hsService == null) ||(a2dpService == null )){
+            return;
+        }
+        List<BluetoothDevice> a2dpConnDevList= a2dpService.getConnectedDevices();
+        List<BluetoothDevice> hfConnDevList= hsService.getConnectedDevices();
+        // Check if the device is in disconnected state and if so return
+        // We ned to connect other profile only if one of the profile is still in connected state
+        // This is required to avoide a race condition in which profiles would
+        // automaticlly connect if the disconnection is initiated within 6 seconds of connection
+        //First profile connection being rejected is an exception
+        if((hfConnDevList.isEmpty() && a2dpConnDevList.isEmpty())&&
+            (PROFILE_CONN_CONNECTED  == firstProfileStatus)){
+            return;
+        }
+        if((hfConnDevList.isEmpty()) &&
+            (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
+            hsService.connect(device);
+        }
+        else if((a2dpConnDevList.isEmpty()) &&
+            (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
+            a2dpService.connect(device);
+        }
+    }
+
+     void setProfileAutoConnectionPriority (BluetoothDevice device, int profileId){
+         if (profileId == BluetoothProfile.HEADSET) {
+             HeadsetService  hsService = HeadsetService.getHeadsetService();
+             if ((hsService != null) &&
+                (BluetoothProfile.PRIORITY_AUTO_CONNECT != hsService.getPriority(device))){
+                 hsService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
+             }
+         }
+         else if (profileId ==  BluetoothProfile.A2DP) {
+             A2dpService a2dpService = A2dpService.getA2dpService();
+             if ((a2dpService != null) &&
+                (BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
+                 a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
+             }
+         }
+    }
+
      boolean cancelBondProcess(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
         byte[] addr = Utils.getBytesFromAddress(device.getAddress());
diff --git a/src/com/android/bluetooth/btservice/AdapterState.java b/src/com/android/bluetooth/btservice/AdapterState.java
index f6b4943..0f28b6b 100755
--- a/src/com/android/bluetooth/btservice/AdapterState.java
+++ b/src/com/android/bluetooth/btservice/AdapterState.java
@@ -125,6 +125,7 @@
         @Override
         public void enter() {
             infoLog("Entering On State");
+            mAdapterService.autoConnect();
         }
 
         @Override
diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java
index 4627b77..c2b38f0 100755
--- a/src/com/android/bluetooth/btservice/BondStateMachine.java
+++ b/src/com/android/bluetooth/btservice/BondStateMachine.java
@@ -5,7 +5,11 @@
 package com.android.bluetooth.btservice;
 
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothDevice;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.hid.HidService;
+import com.android.bluetooth.hfp.HeadsetService;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Message;
@@ -165,6 +169,16 @@
                             result = false;
                             transitionTo(mStableState);
                         }
+                        if (newState == BluetoothDevice.BOND_NONE)
+                        {
+                            // Set the profile Priorities to undefined
+                            clearProfilePriorty(dev);
+                        }
+                        else if (newState == BluetoothDevice.BOND_BONDED)
+                        {
+                           // Restore the profile priorty settings
+                           setProfilePriorty(dev);
+                        }
                     }
                     else if(!mDevices.contains(dev))
                         result=true;
@@ -264,6 +278,40 @@
         sendMessage(msg);
     }
 
+    private void setProfilePriorty (BluetoothDevice device){
+        HidService hidService = HidService.getHidService();
+        A2dpService a2dpService = A2dpService.getA2dpService();
+        HeadsetService headsetService = HeadsetService.getHeadsetService();
+
+        if ((hidService != null) &&
+            (hidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)){
+            hidService.setPriority(device,BluetoothProfile.PRIORITY_ON);
+        }
+
+        if ((a2dpService != null) &&
+            (a2dpService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)){
+            a2dpService.setPriority(device,BluetoothProfile.PRIORITY_ON);
+        }
+
+        if ((headsetService != null) &&
+            (headsetService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)){
+            headsetService.setPriority(device,BluetoothProfile.PRIORITY_ON);
+        }
+    }
+
+    private void clearProfilePriorty (BluetoothDevice device){
+        HidService hidService = HidService.getHidService();
+        A2dpService a2dpService = A2dpService.getA2dpService();
+        HeadsetService headsetService = HeadsetService.getHeadsetService();
+
+        if (hidService != null)
+            hidService.setPriority(device,BluetoothProfile.PRIORITY_UNDEFINED);
+        if(a2dpService != null)
+            a2dpService.setPriority(device,BluetoothProfile.PRIORITY_UNDEFINED);
+        if(headsetService != null)
+            headsetService.setPriority(device,BluetoothProfile.PRIORITY_UNDEFINED);
+    }
+
     private void infoLog(String msg) {
         Log.i(TAG, msg);
     }
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 49fc3f5..9f6f6da 100755
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -34,6 +34,7 @@
     private static final boolean DBG = true;
     private static final String TAG = "HeadsetService";
     private HeadsetStateMachine mStateMachine;
+    private static HeadsetService sHeadsetService;
 
     protected String getName() {
         return TAG;
@@ -54,6 +55,7 @@
         } catch (Exception e) {
             Log.w(TAG,"Unable to register headset receiver",e);
         }
+        setHeadsetService(this);
         return true;
     }
 
@@ -72,6 +74,7 @@
             mStateMachine.cleanup();
             mStateMachine=null;
         }
+        clearHeadsetService();
         return true;
     }
 
@@ -252,7 +255,41 @@
     };
 
     //API methods
-    boolean connect(BluetoothDevice device) {
+    public static synchronized HeadsetService getHeadsetService(){
+        if (sHeadsetService != null && sHeadsetService.isAvailable()) {
+            if (DBG) Log.d(TAG, "getHeadsetService(): returning " + sHeadsetService);
+            return sHeadsetService;
+        }
+        if (DBG)  {
+            if (sHeadsetService == null) {
+                Log.d(TAG, "getHeadsetService(): service is NULL");
+            } else if (!(sHeadsetService.isAvailable())) {
+                Log.d(TAG,"getHeadsetService(): service is not available");
+            }
+        }
+        return null;
+    }
+
+    private static synchronized void setHeadsetService(HeadsetService instance) {
+        if (instance != null && instance.isAvailable()) {
+            if (DBG) Log.d(TAG, "setHeadsetService(): set to: " + sHeadsetService);
+            sHeadsetService = instance;
+        } else {
+            if (DBG)  {
+                if (sHeadsetService == null) {
+                    Log.d(TAG, "setHeadsetService(): service not available");
+                } else if (!sHeadsetService.isAvailable()) {
+                    Log.d(TAG,"setHeadsetService(): service is cleaning up");
+                }
+            }
+        }
+    }
+
+    private static synchronized void clearHeadsetService() {
+        sHeadsetService = null;
+    }
+
+    public boolean connect(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH ADMIN permission");
 
@@ -283,7 +320,7 @@
         return true;
     }
 
-    List<BluetoothDevice> getConnectedDevices() {
+    public List<BluetoothDevice> getConnectedDevices() {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return mStateMachine.getConnectedDevices();
     }
@@ -298,7 +335,7 @@
         return mStateMachine.getConnectionState(device);
     }
 
-    boolean setPriority(BluetoothDevice device, int priority) {
+    public boolean setPriority(BluetoothDevice device, int priority) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         Settings.Secure.putInt(getContentResolver(),
@@ -308,7 +345,7 @@
         return true;
     }
 
-    int getPriority(BluetoothDevice device) {
+    public int getPriority(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         int priority = Settings.Secure.getInt(getContentResolver(),
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index a58349e..51af3ce 100755
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -329,7 +329,11 @@
                     //reject the connection and stay in Disconnected state itself
                     disconnectHfpNative(getByteAddress(device));
                     // the other profile connection should be initiated
-                    broadcastConnectOtherProfilesIntent(device);
+                    AdapterService adapterService = AdapterService.getAdapterService();
+                    if ( adapterService != null) {
+                        adapterService.connectOtherProfile(device,
+                                                           AdapterService.PROFILE_CONN_REJECTED);
+                    }
                 }
                 break;
             case HeadsetHalConstants.CONNECTION_STATE_CONNECTED:
@@ -355,9 +359,12 @@
                               " bondState=" + device.getBondState());
                     disconnectHfpNative(getByteAddress(device));
                     // the other profile connection should be initiated
-                    broadcastConnectOtherProfilesIntent(device);
+                    AdapterService adapterService = AdapterService.getAdapterService();
+                    if ( adapterService != null) {
+                        adapterService.connectOtherProfile(device,
+                                                           AdapterService.PROFILE_CONN_REJECTED);
+                    }
                 }
-
                 break;
             case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING:
                 Log.w(TAG, "Ignore HF DISCONNECTING event, device: " + device);
@@ -1239,15 +1246,6 @@
         mService.sendBroadcast(intent, HeadsetService.BLUETOOTH_PERM);
     }
 
-    private void broadcastConnectOtherProfilesIntent(BluetoothDevice device) {
-        // send other profile connect intent
-        if (DBG) log("Other Profile Connect intent sent " + device);
-
-        Intent intent = new Intent(BluetoothProfile.ACTION_CONNECT_OTHER_PROFILES);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        mService.sendBroadcast(intent, HeadsetService.BLUETOOTH_PERM);
-    }
-
     private void broadcastAudioState(BluetoothDevice device, int newState, int prevState) {
         if(prevState == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
             // When SCO gets disconnected during call transfer, Virtual call
diff --git a/src/com/android/bluetooth/hid/HidService.java b/src/com/android/bluetooth/hid/HidService.java
index 2ed02b7..2f3c6de 100755
--- a/src/com/android/bluetooth/hid/HidService.java
+++ b/src/com/android/bluetooth/hid/HidService.java
@@ -38,6 +38,7 @@
 
     private Map<BluetoothDevice, Integer> mInputDevices;
     private boolean mNativeAvailable;
+    private static HidService sHidService;
 
     private static final int MESSAGE_CONNECT = 1;
     private static final int MESSAGE_DISCONNECT = 2;
@@ -68,6 +69,7 @@
         mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>());
         initializeNative();
         mNativeAvailable=true;
+        setHidService(this);
         return true;
     }
 
@@ -86,9 +88,45 @@
             mInputDevices.clear();
             mInputDevices = null;
         }
+        clearHidService();
         return true;
     }
 
+    public static synchronized HidService getHidService(){
+        if (sHidService != null && sHidService.isAvailable()) {
+            if (DBG) Log.d(TAG, "getHidService(): returning " + sHidService);
+            return sHidService;
+        }
+        if (DBG)  {
+            if (sHidService == null) {
+                Log.d(TAG, "getHidService(): service is NULL");
+            } else if (!(sHidService.isAvailable())) {
+                Log.d(TAG,"getHidService(): service is not available");
+            }
+        }
+        return null;
+    }
+
+    private static synchronized void setHidService(HidService instance) {
+        if (instance != null && instance.isAvailable()) {
+            if (DBG) Log.d(TAG, "setHidService(): set to: " + sHidService);
+            sHidService = instance;
+        } else {
+            if (DBG)  {
+                if (sHidService == null) {
+                    Log.d(TAG, "setHidService(): service not available");
+                } else if (!sHidService.isAvailable()) {
+                    Log.d(TAG,"setHidService(): service is cleaning up");
+                }
+            }
+        }
+    }
+
+    private static synchronized void clearHidService() {
+        sHidService = null;
+    }
+
+
     private final Handler mHandler = new Handler() {
 
         @Override
@@ -359,7 +397,7 @@
         return inputDevices;
     }
 
-    boolean setPriority(BluetoothDevice device, int priority) {
+    public boolean setPriority(BluetoothDevice device, int priority) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         Settings.Secure.putInt(getContentResolver(),
@@ -369,7 +407,7 @@
         return true;
     }
 
-    int getPriority(BluetoothDevice device) {
+    public  int getPriority(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH_ADMIN permission");
         int priority = Settings.Secure.getInt(getContentResolver(),