1. 程式人生 > >Android 藍芽服務端實現

Android 藍芽服務端實現

package com.ibrobo.robotbingo.common.bluetooth.service;

import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothAdapter;
import com.infrastructure.utils.LogUtils;
import android.bluetooth.BluetoothSocket;
import android.os.HandlerThread;
import java.io.OutputStream;
import java.io.InputStream;
import android.os.Message;
import android.os.Handler;
import android.os.Looper;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 藍芽通訊基礎服務框架
 * BluetoothBaseService
 */
public class BBS {

    private static final int MSG_BLUETOOTH_START = 0;     //藍芽開始
    private static final int MSG_BLUETOOTH_CLOSE = 1;     //藍芽關閉
    private static final int MSG_BLUETOOTH_LISTEN = 2;    //藍芽監聽
    private static final int MSG_BLUETOOTH_CONNECTED = 3; //藍芽連線

    private final BluetoothAdapter mBluetoothAdapter;              //藍芽操作Adapter
    private BluetoothStatusHandler mBluetoothStatusHandler = null;  //藍芽工作處理集
    private BluetoothReadHandler mBluetoothReadHandler = null;      //藍芽工作處理集

    public BBS(){
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        HandlerThread handlerThread1 = new HandlerThread("BluetoothStatusHandler");
        handlerThread1.start();
        mBluetoothStatusHandler = new BluetoothStatusHandler(handlerThread1.getLooper());

        HandlerThread handlerThread2 = new HandlerThread("BluetoothReadHandler");
        handlerThread2.start();
        mBluetoothReadHandler = new BluetoothReadHandler(handlerThread2.getLooper());

    }


    private static final int READ_OPEN = 1;
    private static final int READ_CLOSE = 2;
    private static final int READ = 3;

    private class BluetoothReadHandler extends Handler{
        private AtomicBoolean isOpen = new AtomicBoolean(false);

        BluetoothReadHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what){
                case READ:
                    if(isOpen.get() && onPushListener != null){
                        LogUtils.bluetooth("read input stream....");
                        try{
                            if (mConnectedHandler != null) {
                                mConnectedHandler.read();
                            }
                        sendEmptyMessage(READ);
                        }catch (Exception e){
                            e.printStackTrace();
                            bluetoothErrorHandler(ERROR_BLUETOOTH_READ, new RuntimeException("bluetooth read stream fail!"));
                        }
                    }
                    break;
                case READ_OPEN:
                    isOpen.set(true);
                    synchronized (this){
                        notify();
                    }
                    sendEmptyMessage(READ);
                    break;

                case READ_CLOSE:
                    removeMessages(READ);
                    isOpen.set(false);
                    synchronized (this){
                        notify();
                    }
                    break;
            }
        }

        public void open(){
            synchronized (this){
                try {
                    sendEmptyMessage(READ_OPEN);
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void close(){
            synchronized (this){
                try {
                    sendEmptyMessage(READ_CLOSE);
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    /**
     * 藍芽狀態管理
     */
    private class BluetoothStatusHandler extends Handler{

        private int BBSmsg; //連線流程控制

        BluetoothStatusHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what){
                case MSG_BLUETOOTH_START:
                    closeBluetoothDeviceHandler();
                    boolean openSucess = openBluetoothDeviceHandler();
                    if(openSucess){
                        BBSmsg = MSG_BLUETOOTH_START; //設定狀態為藍芽開啟
                        bluetoothStatusChangeHandler(STATUS_BLUETOOTH_OPEN, "bluetooth opend!");
                        sendEmptyMessage(MSG_BLUETOOTH_LISTEN);
                    }else {
                        bluetoothErrorHandler(ERROR_BLUETOOTH_UNABLE, new RuntimeException("bluetooth unable!"));
                    }
                    break;

                case MSG_BLUETOOTH_LISTEN:
                    if(BBSmsg == MSG_BLUETOOTH_START){
                        BBSmsg = MSG_BLUETOOTH_LISTEN;
                        acceptBluetoothConnectHandler();
                        bluetoothStatusChangeHandler(STATUS_BLUETOOTH_SERVICE_ACCEPTED, "bluetooth service accepted!");
                    }else {
                        LogUtils.bluetooth("status error no handle:" + BBSmsg);
                    }
                    break;

                case MSG_BLUETOOTH_CONNECTED:
                    if(BBSmsg == MSG_BLUETOOTH_LISTEN){
                        Object socket = msg.obj;
                        if (socket != null) {
                            closeBluetoothDeviceHandler();
                            mConnectedHandler = new ConnectedHandler((BluetoothSocket) socket);
                            if (mConnectedHandler.connectedSuccess()) {
                                    //開啟讀資料
                                mBluetoothReadHandler.open();
                                BBSmsg = MSG_BLUETOOTH_CONNECTED;
                                bluetoothStatusChangeHandler(STATUS_BLUETOOTH_CONNECTED, "bluetooth build connect!");
                            } else {
                                bluetoothErrorHandler(ERROR_BLUETOOTH_CONNECT, new RuntimeException("bluetooth service build error!"));
                            }
                        } else {
                            bluetoothErrorHandler(ERROR_BLUETOOTH_CONNECT, new RuntimeException("bluetooth service build error!"));
                        }
                    }else {
                        LogUtils.bluetooth("status error no handle:" + BBSmsg);
                    }
                    break;

                case MSG_BLUETOOTH_CLOSE:
                    BBSmsg = MSG_BLUETOOTH_CLOSE;
                    closeBluetoothDeviceHandler();
                    bluetoothStatusChangeHandler(STATUS_BLUETOOTH_CLOSE, "bluetooth close!");
                    break;

                default:
                    break;
            }
        }
    }

    /**
     * 傳送開啟藍芽命令
     */
    public void open(){
        LogUtils.bluetooth("open");
        mBluetoothStatusHandler.sendEmptyMessage(MSG_BLUETOOTH_START);
    }

    /**
     * 傳送關閉藍芽命令
     */
    public void close(){
        LogUtils.bluetooth("close");
        mBluetoothStatusHandler.sendEmptyMessage(MSG_BLUETOOTH_CLOSE);
    }

    //private 檢查藍芽狀態並開啟藍芽,整體檢查返回狀態
    private boolean openBluetoothDeviceHandler() {

        if (mBluetoothAdapter == null) {
            //藍芽模組不可用
            return false;
        }

        //確保藍芽開啟
        if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
            int MAX_COUNT = 10;
            int tryCount = 0;
            boolean enable = false;
            while(!enable){
                //檢查是否開啟完成
                enable = mBluetoothAdapter.isEnabled();
                if(tryCount > MAX_COUNT){
                    return false;
                }
                try {
                    tryCount++;
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }


    /**
     * private 關閉藍芽,整體檢查返回狀態
     */
    private void closeBluetoothDeviceHandler() {
        //關閉讀資料
        mBluetoothReadHandler.close();

        if (mConnectedHandler != null) {
            mConnectedHandler.cancel();
            mConnectedHandler = null;
        }
        if (mAcceptManagerThread != null) {
            mAcceptManagerThread.cancel();
            mAcceptManagerThread = null;
        }
    }

    private static final String NAME_SECURE = "BluetoothChatSecure";
    private static final String NAME_INSECURE = "BluetoothChatInsecure";
    private static final UUID MY_UUID_SECURE = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    private static final UUID MY_UUID_INSECURE = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
    //private static final UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    private volatile ConnectedHandler mConnectedHandler;

    /**
     * private 進入藍芽監聽模式
     * 開始啟動監聽模式
     */
    private void acceptBluetoothConnectHandler(){
        closeBluetoothDeviceHandler();
        mAcceptManagerThread = new AcceptManagerThread();
        mAcceptManagerThread.start();
    }

    private AcceptManagerThread mAcceptManagerThread;
    private class AcceptManagerThread extends Thread{
        //private final AcceptThread mSecureAcceptThread;
        private final AcceptThread mInsecureAcceptThread;

        AcceptManagerThread(){
            //mSecureAcceptThread = new AcceptThread(true);
            mInsecureAcceptThread = new AcceptThread(false);
        }

        @Override
        public void run() {
            //Future<BluetoothSocket> f1 = pool.submit(mSecureAcceptThread);
            Future<BluetoothSocket> f2 = pool.submit(mInsecureAcceptThread);
            try {
//                BluetoothSocket socket1 = f1.get();
//                BluetoothSocket socket2 = f2.get();
//                if(socket1 != null || socket2 != null){
//                    //啟動連結流程
//                    Message message = Message.obtain();
//                    if(f1.get() != null){
//                        message.obj = f1.get();
//                    }else {
//                        message.obj = f2.get();
//                    }
//                    message.what = MSG_BLUETOOTH_CONNECTED;
//                    mBluetoothStatusHandler.sendMessage(message);
//                }else {
//                    throw new RuntimeException("bluetooth service build error!");
//                }
                BluetoothSocket socket2 = f2.get();
                if(socket2 != null){
                    //啟動連結流程
                    Message message = Message.obtain();
                    message.obj = f2.get();
                    message.what = MSG_BLUETOOTH_CONNECTED;
                    mBluetoothStatusHandler.sendMessage(message);
                }else {
                    throw new RuntimeException("bluetooth service build error!");
                }
            } catch (Exception e) {
                e.printStackTrace();
                bluetoothErrorHandler(ERROR_BLUETOOTH_SERVICE_ACCEPT, new RuntimeException("bluetooth service build error!"));
            }
        }

        public void cancel() {
            //mSecureAcceptThread.cancel();
            mInsecureAcceptThread.cancel();
        }
    }

    private static final ExecutorService pool = Executors.newFixedThreadPool(2);
    private class AcceptThread implements Callable<BluetoothSocket> {
        private final BluetoothServerSocket mmServerSocket;
        private String mSocketType;
        public AcceptThread(boolean secure) {
            BluetoothServerSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";
            try {
                if (secure) {
                    tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
                            MY_UUID_SECURE);
                } else {
                    tmp = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(
                            NAME_INSECURE, MY_UUID_INSECURE);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            mmServerSocket = tmp;
        }

        @Override
        public BluetoothSocket call() throws Exception {
            //進入監聽狀態
            BluetoothSocket socket;
            try {
                if (mmServerSocket != null) {
                    LogUtils.bluetooth("accept start");
                    socket = mmServerSocket.accept();
                    LogUtils.bluetooth("accept end");
                } else {
                    LogUtils.bluetooth("mmServerSocket = null");
                    return null;
                }
            } catch (Exception e) {
                e.printStackTrace();
                LogUtils.bluetooth("accept error");
                return null;
            }

            LogUtils.bluetooth("return:" + socket);
            //取消
            mAcceptManagerThread.cancel();

            return socket;
        }

        public void cancel() {
            LogUtils.bluetooth("Socket Type" + mSocketType + "cancel" + this);
            try {
                mmServerSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
                bluetoothErrorHandler(ERROR_BLUETOOTH_CLOSE, e);
            }
        }
    }

    private class ConnectedHandler {
        private static final int READ_MAX = 256;
        private final byte[] bytes = new byte[READ_MAX];
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        private final String mmDevice;

        public ConnectedHandler(BluetoothSocket socket) {
            mmSocket = socket;
            mmDevice = socket.getRemoteDevice().getName();
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (Exception e) {
                e.printStackTrace();
            }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public boolean connectedSuccess(){
            return mmInStream != null && mmOutStream != null;
        }

        public void read() throws Exception {
            int readCount = mmInStream.read(bytes);
            if(onPushListener != null){
                byte[] datas = new byte[readCount];
                System.arraycopy(bytes, 0, datas, 0, readCount);
                onPushListener.onDecode(datas);
            }

        }

        public void write(byte[] buffer) throws Exception {
            mmOutStream.write(buffer);
        }

        public void cancel() {
            try {
                mmInStream.close();
                mmOutStream.close();
                mmSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
                bluetoothErrorHandler(ERROR_BLUETOOTH_CLOSE, e);
            }
        }

        public String getMmDevice() {
            return mmDevice;
        }
    }


    /**
     * 傳送訊息
     */
    public void write(byte[] out) {
        try{
           if (mConnectedHandler != null) {
               mConnectedHandler.write(out);
           }
        }catch (Exception e){
            e.printStackTrace();
            bluetoothErrorHandler(ERROR_BLUETOOTH_WRITE, e);
        }
    }

    /**
     * 藍芽狀態變化
     */
    private static final int ERROR_BLUETOOTH_UNABLE = 2;            //藍芽不可用異常
    private static final int ERROR_BLUETOOTH_CLOSE = 3;             //藍芽關閉異常
    private static final int ERROR_BLUETOOTH_READ = 4;              //藍芽讀取異常
    private static final int ERROR_BLUETOOTH_WRITE = 5;             //藍芽寫異常
    private static final int ERROR_BLUETOOTH_CONNECT = 6;           //藍芽連線異常
    private static final int ERROR_BLUETOOTH_SERVICE_ACCEPT = 7;    //藍芽服務建立異常

    private static final int STATUS_BLUETOOTH_OPEN = 8;                     //藍芽開啟
    private static final int STATUS_BLUETOOTH_SERVICE_ACCEPTED = 9;         //藍芽服務建立
    private static final int STATUS_BLUETOOTH_CONNECTED = 10;               //藍芽連線建立
    private static final int STATUS_BLUETOOTH_CLOSE = 11;                   //藍芽關閉

    private void bluetoothErrorHandler(int errorCount, Exception e){
        switch (errorCount){
            case ERROR_BLUETOOTH_UNABLE:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothUnableError(e);
                }
                break;

            case ERROR_BLUETOOTH_SERVICE_ACCEPT:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothServiceAcceptError(e);
                }
                break;

            case ERROR_BLUETOOTH_CONNECT:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothConnectError(e);
                }
                break;

            case ERROR_BLUETOOTH_READ:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothReadError(e);
                }
                break;

            case ERROR_BLUETOOTH_WRITE:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothWriteError(e);
                }
                break;

            case ERROR_BLUETOOTH_CLOSE:
                if(onBluetoothErrorListener != null){
                    onBluetoothErrorListener.bluetoothCloseError(e);
                }
                break;

            default:
                break;
        }
    }

    private void bluetoothStatusChangeHandler(int statusCount, String statusMessage){
        LogUtils.bluetooth(statusMessage + "  status count:  " + statusCount);
        switch (statusCount){
            case STATUS_BLUETOOTH_OPEN:
                if(onBluetoothStatusListener != null){
                    //獲取本機藍芽資訊
                    String localAddress = mBluetoothAdapter.getAddress();
                    String localName = mBluetoothAdapter.getName();
                    LogUtils.bluetooth("local bluetooth message [address:" + localAddress + ",name:" + localName);
                    onBluetoothStatusListener.bluetoothOpened(statusMessage, localAddress, localName);
                }
                break;
            case STATUS_BLUETOOTH_SERVICE_ACCEPTED:
                if(onBluetoothStatusListener != null){
                    LogUtils.bluetooth("bluetooth accepted:");
                    onBluetoothStatusListener.bluetoothAccepted(statusMessage);
                }
                break;


            case STATUS_BLUETOOTH_CONNECTED:
                if(onBluetoothStatusListener != null){
                    LogUtils.bluetooth("bluetooth connected:" + mConnectedHandler.getMmDevice());
                    onBluetoothStatusListener.bluetoothConnected(mConnectedHandler.getMmDevice());
                }
                break;

            case STATUS_BLUETOOTH_CLOSE:
                if(onBluetoothStatusListener != null){
                    onBluetoothStatusListener.bluetoothClosed(statusMessage);
                }
                break;

            default:
                break;
        }
    }


    public void setOnBluetoothErrorListener(OnBluetoothErrorListener onBluetoothErrorListener) {
        this.onBluetoothErrorListener = onBluetoothErrorListener;
    }
    private volatile OnBluetoothErrorListener onBluetoothErrorListener;
    interface OnBluetoothErrorListener{
        void bluetoothUnableError(Exception e);
        void bluetoothServiceAcceptError(Exception e);
        void bluetoothConnectError(Exception e);
        void bluetoothReadError(Exception e);
        void bluetoothWriteError(Exception e);
        void bluetoothCloseError(Exception e);
    }

    public void setOnBluetoothStatusListener(OnBluetoothStatusListener onBluetoothStatusListener) {
        this.onBluetoothStatusListener = onBluetoothStatusListener;
    }
    private volatile OnBluetoothStatusListener onBluetoothStatusListener;
    interface OnBluetoothStatusListener {
        void bluetoothOpened(String message, String localAddress, String localName);
        void bluetoothAccepted(String message);
        void bluetoothConnected(String message);
        void bluetoothClosed(String message);
    }

    public void setOnPushListener(OnPushListener onPushListener) {
        this.onPushListener = onPushListener;
    }
    private volatile OnPushListener onPushListener;
    interface OnPushListener{
        void onDecode(byte[] datas);
    }
}

package com.ibrobo.robotbingo.common.bluetooth.service;

import com.infrastructure.utils.LogUtils;

/**
 * 藍芽框架控制介面
 */
public class BBSCommander implements
        BBS.OnPushListener,
        BBS.OnBluetoothErrorListener,
        BBS.OnBluetoothStatusListener{

    private static final BBS BBS = new BBS();

    @Override
    public void bluetoothOpened(String message, String localAddress, String localName) {
        LogUtils.bluetooth("bluetooth open!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothOpened(message);
        }
    }

    @Override
    public void bluetoothAccepted(String message) {
        LogUtils.bluetooth("bluetooth bluetoothAccepted!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothAccepted(message);
        }
    }

    @Override
    public void bluetoothConnected(String device) {
        LogUtils.bluetooth("bluetooth connected!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothConnected(device);
        }
    }

    @Override
    public void bluetoothClosed(String message) {
        LogUtils.bluetooth("bluetooth close!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothClosed(message);
        }
    }

    @Override
    public void bluetoothServiceAcceptError(Exception error) {
        LogUtils.bluetooth(error + "bluetooth service build error!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothError(error);
        }
        BBS.open();
    }

    @Override
    public void bluetoothConnectError(Exception error) {
        LogUtils.bluetooth(error + "bluetooth connect error!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothError(error);
        }
        BBS.open();
    }

    @Override
    public void bluetoothReadError(Exception error) {
        LogUtils.bluetooth(error + "bluetooth read error!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothError(error);
        }
        BBS.open();
    }

    @Override
    public void bluetoothWriteError(Exception error) {
        LogUtils.bluetooth(error + "bluetooth write error!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothError(error);
        }
        BBS.open();
    }

    @Override
    public void bluetoothUnableError(Exception error) {
        LogUtils.bluetooth("bluetooth unable!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothUnable(error);
        }
    }

    @Override
    public void bluetoothCloseError(Exception error) {
        LogUtils.bluetooth("bluetooth close error!");
        if(onBluetoothStatusChangeListener != null){
            onBluetoothStatusChangeListener.bluetoothError(error);
        }
    }

    @Override
    public void onDecode(byte[] datas) {
        if(mOnDecoder != null){
            mOnDecoder.onDecode(datas);
        }
    }

    private static class SingletonInstance {
        private static final BBSCommander mInstance = new BBSCommander();
    }

    public static BBSCommander getInstance(){
        return SingletonInstance.mInstance;
    }

    public void init(){
        BBS.setOnBluetoothStatusListener(this);
        BBS.setOnBluetoothErrorListener(this);
        BBS.setOnPushListener(this);
    }

    public void open(){
        BBS.open();
    }

    public void close(){
        BBS.close();
    }

    public void write(byte[] bytes){
        BBS.write(bytes);
    }

    public void setOnBluetoothStatusChangeListener(OnBluetoothStatusChangeListener onBluetoothStatusChangeListener) {
        this.onBluetoothStatusChangeListener = onBluetoothStatusChangeListener;
    }

    private volatile OnBluetoothStatusChangeListener onBluetoothStatusChangeListener;
    public interface OnBluetoothStatusChangeListener{
        void bluetoothUnable(Exception message);
        void bluetoothError(Exception error);
        void bluetoothOpened(String message);
        void bluetoothAccepted(String message);
        void bluetoothConnected(String message);
        void bluetoothClosed(String message);
    }


    private volatile OnDecoder mOnDecoder;
    public void setOnDecoder(OnDecoder mOnDecoder) {
        this.mOnDecoder = mOnDecoder;
    }

    public interface OnDecoder {
        void onDecode(byte[] bytes);
    }

}