/// <summary>
        /// Called when an intent is received from "StartService" requesting some action.
        /// The command is put onto the message queue.
        /// </summary>
        /// <param name="intent">The received intent</param>
        /// <param name="flags">not used</param>
        /// <param name="startId">not used</param>
        /// <returns></returns>
        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            string[] extras = new string[] { BundleConst.bundleCmdTag, BundleConst.bundleAddrTag, BundleConst.bundleValTag };
            AppLog.Log("RCS-StartCommandResult");
            if (intent == null)
            {
                AppLog.Log("RCS-StartCommandResult - Intent is null");
                return(StartCommandResult.Sticky);;
            }

            try
            {
                Message msg = handler.ObtainMessage();
                msg.Arg1 = startId;

                msg.What = (int)AppConst.MsgPrio.low;

                foreach (string s in extras)
                {
                    if (intent.Extras.ContainsKey(s))
                    {
                        msg.Data.PutString(s, intent.GetStringExtra(s));
                    }
                }
                if (intent.Extras.ContainsKey(BundleConst.bundleDataTag))
                {
                    msg.Data.PutByteArray(BundleConst.bundleDataTag, intent.GetByteArrayExtra(BundleConst.bundleDataTag));
                }

                handler.SendMessage(msg);
            }
            catch (Throwable e)
            {
                AppLog.Log("RCS-StartCommandResult - exception: " + e.ToString());
            }
            return(StartCommandResult.Sticky);
        }
            /// <summary>
            /// The actual read thread
            /// </summary>
            /// <param name="service">Service instance to access public members</param>
            public void ReadProc(object service)
            {
                int     byteRead;                               // We read one byte at a time
                bool    twoByteFlag = false;                    // Set if we've read the first byte of a two-byte sequence
                int     secondByte  = 0;                        // The second byte of the sequence (may denoted device type)
                Message msg;

                serviceContext = (RemoteCommunicationService)service;

                try
                {
                    while ((byteRead = inputStream.ReadByte()) >= 0)
                    {
                        AppLog.Log("RCS-ReadProc; reading: " + byteRead.ToString());

                        switch (serviceContext.serviceState)
                        {
                        case AppConst.ActivityState.idle:         // We shouldn't actually get here as the read thread should only be started in connected state
                            serviceContext.lastReport = 0;
                            twoByteFlag = false;
                            break;

                        case AppConst.ActivityState.connected:
                            if (twoByteFlag)                    // We are connected, but the handshake is in progress. Check if we're reading the second byte of a sequence
                            {
                                secondByte  = byteRead;
                                twoByteFlag = false;

                                if (secondByte < 128)
                                {
                                    UpdateState(AppConst.ActivityState.synced);
                                    serviceContext.lastReport = 0;
                                }
                                break;
                            }

                            if (byteRead < 127)                 // As soon as we have a byte with the top bit clear, the handshake is complete (may occur immediately on reconnecting to device)
                            {
                                UpdateState(AppConst.ActivityState.synced);
                                serviceContext.lastReport = 0;
                                twoByteFlag = false;
                            }
                            else if (byteRead == 128)           // If we've received a byte with the top bit set, send "key up" message to handshake the recorder
                            {
                                twoByteFlag = true;
                                msg         = serviceContext.handler.ObtainMessage();
                                msg.What    = (int)AppConst.MsgPrio.low;
                                msg.Data.PutString(BundleConst.bundleCmdTag, BundleConst.cmdSend);
                                msg.Data.PutByteArray(BundleConst.bundleDataTag, promptSequence);
                                serviceContext.handler.SendMessage(msg);
                            }

                            break;

                        case AppConst.ActivityState.synced:           // If top bit set, the handshake has been lost (eg bluetooth device has been unplugged from recorder)
                            if (byteRead > 127)
                            {
                                UpdateState(AppConst.ActivityState.connected);
                                twoByteFlag = true;
                            }
                            else
                            {
                                twoByteFlag = false;
                                if (serviceContext.lastReport != byteRead)
                                {
                                    SendData(byteRead);
                                }
                                serviceContext.lastReport = byteRead;
                            }
                            break;
                        }
                    }
                }
                // Most likely called when the other thread closes the bluetooth socket on disconnecting
                catch (Throwable e)
                {
                    AppLog.Log("RCS-ReadProc; exception: " + e.ToString());
                    try
                    {
                        inputStream.Close();
                    }
                    catch (Throwable)
                    {
                        AppLog.Log("RCS-ReadProc; stream close exception: " + e.ToString());
                    }
                }
            }
            /// <summary>
            /// Process a message from the queue (CONNECT, DISCONNECT, SEND or STOP)
            /// </summary>
            /// <param name="msg">The message being delivered by the Looper</param>
            public override void HandleMessage(Message msg)
            {
                string command = msg.Data.GetString(BundleConst.bundleCmdTag);
                Intent statusIntent;
                bool   done = true;

                if (!done)
                {
                    return;
                }

                AppLog.Log("RCS-HandleMessage: " + command);

                try
                {
                    switch (command)
                    {
                    case BundleConst.cmdConnect:                                                                 // Connection request
                        if (serviceContext.serviceState != AppConst.ActivityState.idle && serviceContext.serviceState != AppConst.ActivityState.error)
                        {
                            // If we're already connected, prod the UI with the last reported status
                            serviceContext.serviceState = AppConst.ActivityState.connected;
                            outputStream.Write(promptSequence, 0, promptSequence.Length);                                                      // Try to elicit a response in case we were previously connected.
                            SendData(serviceContext.lastReport);
                            return;
                        }

                        try
                        {
                            string deviceAddr = msg.Data.GetString(BundleConst.bundleAddrTag);                   // Get the Bluetooth device address

                            btDevice = BluetoothAdapter.DefaultAdapter.GetRemoteDevice(deviceAddr);
                            btSocket = btDevice.CreateInsecureRfcommSocketToServiceRecord(AppConst.uuid);
                            btSocket.Connect();                                                             // Connect the socket

                            AppLog.Log("RCS-HandleMessage: " + command + "; connected device " + deviceAddr);

                            inputStream  = Stream.Synchronized(btSocket.InputStream);
                            outputStream = Stream.Synchronized(btSocket.OutputStream);
                            serviceContext.serviceState = AppConst.ActivityState.connected;
                            readThreadObject            = new ReadThread(inputStream);
                            readThread = new System.Threading.Thread(readThreadObject.ReadProc);                             // Start the read thread
                            readThread.Start(serviceContext);
                            outputStream.Write(promptSequence, 0, promptSequence.Length);                                    // Try to elicit a response in case we were previously connected.
                            AppLog.Log("RCS-HandleMessage: " + command + "; created threads");
                        }
                        catch (Throwable e)
                        {
                            try
                            {
                                if (btSocket != null)
                                {
                                    btSocket.Close();
                                }
                            }
                            catch
                            {
                            }

                            AppLog.Log("RCS-HandleMessage: " + command + "; exception: " + e.ToString());
                            done = false;
                        }

                        statusIntent = new Intent(AppConst.rxIntentName);                                         // Send the status to the activity
                        statusIntent.PutExtra(BundleConst.bundleCmdTag, BundleConst.bundleStatusTag);
                        if (done)
                        {
                            serviceContext.serviceState = AppConst.ActivityState.connected;
                        }
                        else
                        {
                            serviceContext.serviceState = AppConst.ActivityState.error;
                        }
                        statusIntent.PutExtra(BundleConst.bundleValTag, (int)serviceContext.serviceState);
                        serviceContext.SendBroadcast(statusIntent);

                        if (!done)
                        {
                            CloseConnection(msg.Arg1);
                        }
                        break;

                    case BundleConst.cmdDisconnect:                                                                      // Disconnect request
                        CloseConnection(msg.Arg1);
                        serviceContext.serviceState = AppConst.ActivityState.idle;
                        statusIntent = new Intent(AppConst.rxIntentName);
                        statusIntent.PutExtra(BundleConst.bundleCmdTag, BundleConst.bundleStatusTag);
                        statusIntent.PutExtra(BundleConst.bundleValTag, (int)serviceContext.serviceState);
                        serviceContext.SendBroadcast(statusIntent);                                                 // Update status
                        break;

                    case BundleConst.cmdSend:                                                                            // Send data
                        if (serviceContext.serviceState == AppConst.ActivityState.connected || serviceContext.serviceState == AppConst.ActivityState.synced)
                        {
                            try
                            {
                                byte[] devCmd;

                                devCmd = msg.Data.GetByteArray(BundleConst.bundleDataTag);
                                outputStream.Write(devCmd, 0, devCmd.Length);
                                AppLog.Log("RCS-HandleMessage: " + command + "; sent: " + devCmd.ToString());
                            }
                            catch (Throwable e)
                            {
                                AppLog.Log("RCS-HandleMessage: " + command + "; exception: " + e.ToString());
                                done = false;
                            }
                        }
                        else
                        {
                            done = false;
                        }

                        if (!done)                                                                                      // Update status on error
                        {
                            statusIntent = new Intent(AppConst.rxIntentName);
                            statusIntent.PutExtra(BundleConst.bundleCmdTag, BundleConst.bundleStatusTag);
                            statusIntent.PutExtra(BundleConst.bundleValTag, (int)AppConst.ActivityState.error);
                            serviceContext.SendBroadcast(statusIntent);
                            CloseConnection(msg.Arg1);
                        }
                        break;
                    }
                }
                catch (Throwable e)
                {
                    AppLog.Log("RCS-HandleMessage: " + command + "; exception: " + e.ToString());
                }
            }