How to move Bluetooth activity into a Service

Solution 1:

I have written a Bluetooth services which runs in the background and can communicate to any Activity in the application using Messenger http://developer.android.com/guide/components/bound-services.html.

public class PrinterService extends Service {
private BluetoothAdapter mBluetoothAdapter;
public static final String BT_DEVICE = "btdevice";
public static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming
                                            // connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing
                                                // connection
public static final int STATE_CONNECTED = 3; // now connected to a remote
                                                // device
private ConnectThread mConnectThread;
private static ConnectedThread mConnectedThread;
// public mInHangler mHandler = new mInHangler(this);
private static Handler mHandler = null;
public static int mState = STATE_NONE;
public static String deviceName;
public Vector<Byte> packdata = new Vector<Byte>(2048);
public static Device device = null;

@Override
public void onCreate() {
    Log.d("PrinterService", "Service started");
    super.onCreate();
}

@Override
public IBinder onBind(Intent intent) {
    mHandler = ((MyAplication) getApplication()).getHandler();
    return mBinder;
}

public class LocalBinder extends Binder {
    PrinterService getService() {
        return PrinterService.this;
    }
}



private final IBinder mBinder = new LocalBinder();

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("PrinterService", "Onstart Command");
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter != null) {
        device = (Device) intent.getSerializableExtra(BT_DEVICE);
        deviceName = device.getDeviceName();
        String macAddress = device.getMacAddress();
        if (macAddress != null && macAddress.length() > 0) {
            connectToDevice(macAddress);
        } else {
            stopSelf();
            return 0;
        }
    }
    String stopservice = intent.getStringExtra("stopservice");
    if (stopservice != null && stopservice.length() > 0) {
        stop();
    }
    return START_STICKY;
}

private synchronized void connectToDevice(String macAddress) {
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);
    if (mState == STATE_CONNECTING) {
        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }
    mConnectThread = new ConnectThread(device);
    mConnectThread.start();
    setState(STATE_CONNECTING);
}

private void setState(int state) {
    PrinterService.mState = state;
    if (mHandler != null) {
        mHandler.obtainMessage(AbstractActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }
}

public synchronized void stop() {
    setState(STATE_NONE);
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }
    if (mBluetoothAdapter != null) {
        mBluetoothAdapter.cancelDiscovery();
    }
    stopSelf();
}

@Override
public boolean stopService(Intent name) {
    setState(STATE_NONE);
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }
    mBluetoothAdapter.cancelDiscovery();
    return super.stopService(name);
}

private void connectionFailed() {
    PrinterService.this.stop();
    Message msg = mHandler.obtainMessage(AbstractActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(AbstractActivity.TOAST, getString(R.string.error_connect_failed));
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}

private void connectionLost() {
    PrinterService.this.stop();
    Message msg = mHandler.obtainMessage(AbstractActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(AbstractActivity.TOAST, getString(R.string.error_connect_lost));
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}

private static Object obj = new Object();

public static void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (obj) {
        if (mState != STATE_CONNECTED)
            return;
        r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);
}

private synchronized void connected(BluetoothSocket mmSocket, BluetoothDevice mmDevice) {
    // Cancel the thread that completed the connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    mConnectedThread = new ConnectedThread(mmSocket);
    mConnectedThread.start();

    // Message msg =
    // mHandler.obtainMessage(AbstractActivity.MESSAGE_DEVICE_NAME);
    // Bundle bundle = new Bundle();
    // bundle.putString(AbstractActivity.DEVICE_NAME, "p25");
    // msg.setData(bundle);
    // mHandler.sendMessage(msg);
    setState(STATE_CONNECTED);

}

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        this.mmDevice = device;
        BluetoothSocket tmp = null;
        try {
            tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));
        } catch (IOException e) {
            e.printStackTrace();
        }
        mmSocket = tmp;
    }

    @Override
    public void run() {
        setName("ConnectThread");
        mBluetoothAdapter.cancelDiscovery();
        try {
            mmSocket.connect();
        } catch (IOException e) {
            try {
                mmSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            connectionFailed();
            return;

        }
        synchronized (PrinterService.this) {
            mConnectThread = null;
        }
        connected(mmSocket, mmDevice);
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e("PrinterService", "close() of connect socket failed", e);
        }
    }
}

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e("Printer Service", "temp sockets not created", e);
        }
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    @Override
    public void run() {
        while (true) {
            try {
                if (!encodeData(mmInStream)) {
                    mState = STATE_NONE;
                    connectionLost();
                    break;
                } else {
                }
                // mHandler.obtainMessage(AbstractActivity.MESSAGE_READ,
                // bytes, -1, buffer).sendToTarget();
            } catch (Exception e) {
                e.printStackTrace();
                connectionLost();
                PrinterService.this.stop();
                break;
            }

        }
    }

    private byte[] btBuff;


    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);

            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(AbstractActivity.MESSAGE_WRITE, buffer.length, -1, buffer).sendToTarget();
        } catch (IOException e) {
            Log.e("PrinterService", "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmSocket.close();

        } catch (IOException e) {
            Log.e("PrinterService", "close() of connect socket failed", e);
        }
    }

}

public void trace(String msg) {
    Log.d("AbstractActivity", msg);
    toast(msg);
}

public void toast(String msg) {
    Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}

@Override
public void onDestroy() {
    stop();
    Log.d("Printer Service", "Destroyed");
    super.onDestroy();
}

private void sendMsg(int flag) {
    Message msg = new Message();
    msg.what = flag;
    handler.sendMessage(msg);
}

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {//
        if (!Thread.currentThread().isInterrupted()) {
            switch (msg.what) {
            case 3:

                break;

            case 4:

                break;
            case 5:
                break;

            case -1:
                break;
            }
        }
        super.handleMessage(msg);
    }

};
}

UPDATE

you need to use Handler in your MyApplication Class

Handler.Callback realCallback = null;
Handler handler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        if (realCallback != null) {
            realCallback.handleMessage(msg);
        }
    };
};
public Handler getHandler() {
    return handler;
}
public void setCallBack(Handler.Callback callback) {
    this.realCallback = callback;
}