Bluetooth: Introduce BTC Service

Introduce the BTC Service which listen to the Bluetooth
related events and send those events to the connected client.
BT-WLAN coex module would connect to this socket as client and listen
to BT related events

Change-Id: Ic8223d6c761bb9e64ce94b83b2a947c1ad87b1d4
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..ebe45cd
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+        $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BluetoothQcom
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100755
index 0000000..3474e2e
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="qcom.android.bluetooth"
+  android:sharedUserId="android.uid.bluetooth">
+
+    <original-package android:name="qcom.android.bluetooth" />
+
+    <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
+    <application>
+        <service
+            android:name = ".btcservice.BTCService">
+        </service>
+        <receiver
+            android:exported="true"
+            android:name=".btcservice.BTCEventProvider">
+            <intent-filter>
+                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+                <action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
+                <action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
+                <action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
+                <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
+                <action android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+                <action android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+                <action android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+                <action android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+                <action android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/src/qcom/android/bluetooth/btcservice/BTCEventProvider.java b/src/qcom/android/bluetooth/btcservice/BTCEventProvider.java
new file mode 100755
index 0000000..ded8d3c
--- /dev/null
+++ b/src/qcom/android/bluetooth/btcservice/BTCEventProvider.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.android.bluetooth.btcservice;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothInputDevice;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.lang.Object;
+/**
+ * <p> {@link com.android.bluetooth.btservice.BTCEventProvider} is a BroadcastReceiver
+ * which listens to set of Bluetoth related events which required by BTWlan Coex module
+ *  to achieve BT WLAN co-existance
+ * </p>
+ * <p> BTEventProvider is responsible for starting and stopping of
+ * {@link com.android.bluetooth.btservice.BTCService} and
+ * also to send the events via {@link com.android.bluetooth.btservice.BTCService#sendEvent}
+ */
+
+public class BTCEventProvider extends BroadcastReceiver {
+    private static final String TAG = "BTCEventProvider";
+    private static final boolean D = /*Constants.DEBUG*/true;
+    private static final boolean V = true/*Constants.VERBOSE*/;
+    private int state;
+    BTCService.BTCEvent event = BTCService.BTCEvent.BLUETOOTH_NONE;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            state = intent.getIntExtra
+                           (BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothAdapter.STATE_ON == state) {
+                if (V) Log.v(TAG, "Received BLUETOOTH_STATE_ON");
+                ComponentName service = context.startService
+                                      (new Intent(context, BTCService.class));
+                if (service != null) {
+                    event =  BTCService.BTCEvent.BLUETOOTH_ON;
+                } else {
+                    Log.e(TAG, "Could Not Start BTC Service ");
+                    return;
+                }
+            } else if (BluetoothAdapter.STATE_OFF == state) {
+                if (V) Log.v(TAG, "Received BLUETOOTH_STATE_OFF");
+                event =  BTCService.BTCEvent.BLUETOOTH_OFF;
+            }
+        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
+            if (V) Log.v(TAG, "Received ACTION_DISCOVERY_STARTED");
+            event =  BTCService.BTCEvent.BLUETOOTH_DISCOVERY_STARTED;
+        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+            if (V) Log.v(TAG, "Received ACTION_DISCOVERY_STOPPED");
+            event =  BTCService.BTCEvent.BLUETOOTH_DISCOVERY_FINISHED;
+        } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
+            if (V) Log.v(TAG, "Received ACTION_ACL_CONNECTED");
+            event =  BTCService.BTCEvent.BLUETOOTH_DEVICE_CONNECTED;
+        } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+            if (V) Log.v(TAG, "Received ACTION_ACL_DISCONNECTED");
+            event =  BTCService.BTCEvent.BLUETOOTH_DEVICE_DISCONNECTED;
+        } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+            if (V) Log.v(TAG, "ACTION_CONNECTION_STATE_CHANGED");
+            state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothProfile.STATE_CONNECTED == state) {
+                if (V) Log.v(TAG, "BluetoothHeadset.STATE_CONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_HEADSET_CONNECTED;
+            } else if (BluetoothProfile.STATE_DISCONNECTED == state) {
+                if (V) Log.v(TAG, "BluetoothHeadset.STATE_DISCONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_HEADSET_DISCONNECTED;
+            }
+        } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+            if (V) Log.v(TAG, "BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED");
+            state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothProfile.STATE_CONNECTED == state) {
+                if (V) Log.v(TAG, "ACTION_AUDIO_STATE_CHANGED:STATE_CONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_HEADSET_AUDIO_STREAM_STARTED;
+            } else if (BluetoothProfile.STATE_DISCONNECTED == state) {
+                if (V) Log.v(TAG, "ACTION_AUDIO_STATE_CHANGED:STATE_DISCONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_HEADSET_AUDIO_STREAM_STOPPED;
+            }
+        } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
+            if (V) Log.v(TAG, "BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED");
+            state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothProfile.STATE_CONNECTED == state) {
+                if (V) Log.v(TAG, "A2DP: STATE_CONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_AUDIO_SINK_CONNECTED;
+            } else if (BluetoothProfile.STATE_DISCONNECTED == state) {
+                if (V) Log.v(TAG, "A2DP: STATE_DISCONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_AUDIO_SINK_DISCONNECTED;
+            }
+        } else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) {
+            if (V) Log.v(TAG, "BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED");
+            state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothA2dp.STATE_PLAYING == state) {
+                if (V) Log.v(TAG, "A2DP. PLAYING_STATE_CHANGED: CONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_SINK_STREAM_STARTED;
+            } else if (BluetoothA2dp.STATE_NOT_PLAYING == state) {
+                if (V) Log.v(TAG, "A2DP.PLAYING_STATE_CHANGED: DISCONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_SINK_STREAM_STOPPED;
+            }
+        } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
+            if (V) Log.v(TAG, "HID.ACTION_CONNECTION_STATE_CHANGED");
+            state = intent.getIntExtra
+                       (BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothProfile.STATE_CONNECTED == state) {
+                if (V) Log.v(TAG, "HID.CONNECTION_STATE_CHANGED: CONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_INPUT_DEVICE_CONNECTED;
+            } else if (BluetoothProfile.STATE_DISCONNECTED == state) {
+                if (V) Log.v(TAG, "HID.CONNECTION_STATE_CHANGED:DISCONNECTED");
+                event =  BTCService.BTCEvent.BLUETOOTH_INPUT_DEVICE_DISCONNECTED;
+            }
+        }
+        //Don;t send if it is not relavant event
+        if (event != BTCService.BTCEvent.BLUETOOTH_NONE) {
+           int status = BTCService.sendEvent(event);
+           if (status == 0) {
+              if (V) Log.v(TAG, "Event:" + event.getValue() + "Written Succesfully");
+           }
+           else {
+              Log.e(TAG, "Error while sending Event:" + event.getValue());
+           }
+           if (event ==  BTCService.BTCEvent.BLUETOOTH_OFF) {
+               Log.v(TAG, "Stop the BTC Service");
+               context.stopService(new Intent(context, BTCService.class));
+           }
+        }
+    }
+}
diff --git a/src/qcom/android/bluetooth/btcservice/BTCService.java b/src/qcom/android/bluetooth/btcservice/BTCService.java
new file mode 100755
index 0000000..3b453ad
--- /dev/null
+++ b/src/qcom/android/bluetooth/btcservice/BTCService.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.android.bluetooth.btcservice;
+
+import android.app.Service;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.net.Credentials;
+import java.io.OutputStream;
+import android.util.Log;
+import android.os.IBinder;
+import android.content.Intent;
+import android.os.Process;
+import java.nio.ByteBuffer;
+
+/**
+ * <p> {@link com.android.bluetooth.btservice.BTCService} is a background service which starts
+ *  and stops on BLUETOOTH_ON and BLUETOOTH_OFF intents
+ *  Ref: {@see android.bluetooth.BluetoothAdapter#ACTION_STATE_CHANGED}
+ * </p>
+ * <p> {@link com.android.bluetooth.btservice.BTCEventProvider} is the BroadcaseReciever which
+ *  listen to set of bluetooth related intents and responsible for starting and stopping of
+ *  BTCService
+ * </p>
+ * <p> {@link com.android.bluetooth.btservice.BTCService} creates the Local Socket server named as
+ * {@link com.android.bluetooth.btservice.BTCService.BTC_SERVER} and listen for the
+ * incoming connections up on start
+ *
+ * <p> {@link com.android.bluetooth.btservice.BTCService} can accepts the connection from clients
+ * whose uid is either {@link android.os.Process.BLUETOOTH_UID} or ROOT(with UID 0) and discards
+ * all other connections and hence provides the events only to the authenticates processes
+ * </p>
+ *
+ * Once the successful connection is established BTCService pushes the events listed in {@link BTCEvent}
+ * over the socket, Client has to read these data and interpret based on the values {@link BTCEvent}
+ * </p>
+ *
+ * <p> As LocalSocket implementation doesn't  properly propagate the closing of socket to
+ * to the native layets properly, closing the socket at Java layer doesn't invalidate the
+ * socket at the native layers
+ * *** So, It is client's responsibility to close their socket
+ * end just after recieving the {@link BTCEvent.BLUETOOTH_OFF} event
+ * </p>
+ *
+ */
+public class BTCService extends Service
+{
+    public final static String BTC_SERVER = "qcom.btc.server";
+    private static LocalServerSocket mSocket =null;
+    private static LocalSocket mRemoteSocket = null;
+    private static final String LOGTAG = "BTCService";
+    private static OutputStream mOutputStream = null;
+    private static Thread mSocketAcceptThread;
+    private static boolean mLocalConnectInitiated = false;
+    private static final Object mLock = new Object();
+
+    public enum BTCEvent {
+        BLUETOOTH_NONE(0x00),
+        BLUETOOTH_ON(0x20),
+        BLUETOOTH_OFF(0x21),
+        BLUETOOTH_DISCOVERY_STARTED(0x22),
+        BLUETOOTH_DISCOVERY_FINISHED(0x23),
+        BLUETOOTH_DEVICE_CONNECTED(0x24),
+        BLUETOOTH_DEVICE_DISCONNECTED(0x25),
+        BLUETOOTH_HEADSET_CONNECTED(0x40),
+        BLUETOOTH_HEADSET_DISCONNECTED(0x41),
+        BLUETOOTH_HEADSET_AUDIO_STREAM_STARTED(0x42),
+        BLUETOOTH_HEADSET_AUDIO_STREAM_STOPPED(0x43),
+        BLUETOOTH_AUDIO_SINK_CONNECTED(0x60),
+        BLUETOOTH_AUDIO_SINK_DISCONNECTED(0x61),
+        BLUETOOTH_SINK_STREAM_STARTED(0x62),
+        BLUETOOTH_SINK_STREAM_STOPPED(0x63),
+        BLUETOOTH_INPUT_DEVICE_CONNECTED(0x80),
+        BLUETOOTH_INPUT_DEVICE_DISCONNECTED(0x81);
+
+        private int mValue;
+        private BTCEvent(int value) {
+            mValue = value;
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+    }
+
+    public BTCService() {
+        Log.v(LOGTAG, "BTCService");
+    }
+
+    static private void cleanupService() throws java.io.IOException {
+    synchronized (mLock) {
+        if (mSocket != null) {
+            mSocket.close();
+            mSocket = null;
+            Log.v(LOGTAG, "Server Socket closed");
+        }
+        if (mRemoteSocket != null) {
+            mRemoteSocket.close();
+            mRemoteSocket = null;
+            Log.v(LOGTAG, "Client Socket closed");
+        }
+        if( mSocketAcceptThread != null ) {
+            mSocketAcceptThread.interrupt();
+            Log.v(LOGTAG, "Acceptor thread stopped");
+        }
+    }
+    }
+
+    /**
+     * <p> Sends the BTCEvent over the valid socket connection
+     * </p>
+     * @param event {@link BTCEvent} object
+     * @return 0 on success,
+     *        -1 when there is no client connection available,
+     *        -2 when there is issue while writing on client socket.
+     */
+    static public int sendEvent(BTCEvent event) {
+        Log.v(LOGTAG, "sendEvent: " + event.getValue());
+        if (mRemoteSocket == null) {
+            Log.v(LOGTAG, "No Valid Connection" );
+            return -1;
+        }
+
+        ByteBuffer buffer = ByteBuffer.allocate(4);
+        buffer.putInt(event.getValue());
+
+        try {
+            mOutputStream.write(buffer.array());
+        }
+        catch (java.io.IOException e) {
+            Log.e(LOGTAG, "Error while posting the event: " + event + "Error:" + e);
+            Log.e(LOGTAG, "connectoin is closed for Unknown reason, restart the acceptor thread ");
+            startListener();
+            return -2;
+        }
+        return 0;
+    }
+
+    static private void startListener() {
+        try  {
+            cleanupService();
+            mSocket = new LocalServerSocket(BTC_SERVER);
+        } catch (java.io.IOException e) {
+            Log.e(LOGTAG, "Error While cleanupService:"+ e);
+            return;
+        }
+        mSocketAcceptThread = new Thread() {
+        @Override
+        public void run() {
+        do {
+           try {
+               Log.v(LOGTAG, "Waiting for connection...");
+               try {
+                   mRemoteSocket = mSocket.accept();
+               } catch (java.io.IOException e) {
+                   Log.e(LOGTAG, "Error While accepting the connection: " + e);
+                   //Keep back in accpetor loop
+                   mRemoteSocket = null;
+               }
+               if (mLocalConnectInitiated) {
+                   //This is just a local connection
+                   //to unblock the accept
+                   Log.e(LOGTAG, "Terminator in action: ");
+                   cleanupService();
+                   mLocalConnectInitiated = false;
+                   return;
+               }
+               if (mRemoteSocket != null) {
+                   Log.v(LOGTAG, "Got socket: " + mRemoteSocket);
+                   Credentials cred = null;
+                   try {
+                       cred = mRemoteSocket.getPeerCredentials();
+                   } catch (java.io.IOException e) {
+                       Log.e(LOGTAG, "Getting peer credential" + "Error:" + e);
+                       cred = null;//Pas through, so that it fails and back in loop
+                   }
+                   if (cred != null) {
+                       if (cred.getUid() != 0 && cred.getUid() != Process.BLUETOOTH_UID) {
+                           Log.e(LOGTAG, "Peer with UID: " + cred.getUid() +" is not authenticated");
+                           Log.e(LOGTAG, "Close the connection and back in acceptor loop");
+                           mRemoteSocket.close();
+                           mRemoteSocket = null;
+                       } else {
+                           //Only ROOT and BLUETOOTH connections are
+                           //are accepted
+                           Log.v(LOGTAG, "Authenticated socket: " + mRemoteSocket);
+                           mOutputStream = mRemoteSocket.getOutputStream();
+                           //Close the  Server Socket
+                           mSocket.close();
+                           mSocket = null;
+                           return;
+                       }
+                  } else {
+                      Log.e(LOGTAG, "Not able to get the credentais, discard connection");
+                      mRemoteSocket.close();
+                      mRemoteSocket = null;
+                  }
+
+               } else {
+                   Log.e(LOGTAG, "Remote socket unavaialble");
+                   //Keep back in accpetor loop
+                   mRemoteSocket = null;
+               }
+           } catch (Exception e) {
+                Log.d(LOGTAG,  "RunningThread InterruptedException");
+                e.printStackTrace();
+                Thread.currentThread().interrupt();
+           }
+       } while ((!Thread.currentThread().isInterrupted()));
+       }
+       };
+       mSocketAcceptThread.start();
+    }
+
+    private void closeServerSocket() {
+        Thread t = new Thread() {
+        @Override
+        public void run() {
+            try {
+                LocalSocketAddress locSockAddr = new LocalSocketAddress(BTC_SERVER);
+                LocalSocket terminator = new LocalSocket();
+                Log.e(LOGTAG, "Trying to unblock by connecting");
+                mLocalConnectInitiated = true;
+                terminator.connect(locSockAddr);
+                terminator.close();
+                Log.e(LOGTAG, "Terminator closed");
+            } catch (java.io.IOException e) {
+                Log.e(LOGTAG, "cant connect: " + e);
+            }
+        }
+        };
+        t.start();
+    }
+
+    @Override
+    public void onCreate() {
+        Log.v(LOGTAG, "onCreate");
+        super.onCreate();
+
+        Log.v(LOGTAG, "calling startListener");
+        startListener();
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.v(LOGTAG, "onDestroy");
+        try {
+
+            if (mSocket != null) {
+                //This is the case where
+                //server socket is still stuck in accept()
+                closeServerSocket();
+            }
+            cleanupService();
+        }
+        catch (java.io.IOException e) {
+            Log.e(LOGTAG, "in onDestroy: " + e);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent in) {
+        Log.v(LOGTAG, "onBind");
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(LOGTAG, "onStart Command called!!");
+        //Make this restarable service by
+        //Android app manager
+        return START_STICKY;
+   }
+}