安卓藍牙操作+藍牙工具類


由於前段時間,需要藍牙操作一些東西。但是沒有寫過藍牙連接與藍牙操作等一系列的東西。

然后就去網上找找大家寫的。到現在。已經結束了這個藍牙的開發。

安卓端藍牙操作。主要需要如下類

BluetoothAdapter  通過名字,可以了解到這是一個藍牙適配器的類。可以獲取到藍牙的狀態。開關,。掃描等一系列的常規操作
BluetoothSocket    這個呢,是一個藍牙的socket。不做過多的介紹。和普通socket一樣
BluetoothDevice   這個類是獲取遠程設備的類。


有了上面3個類。藍牙的基本操作就可以實現了。
當然。,藍牙的操作需要廣播來支持、。下面是具體的代碼。

藍牙相關廣播

 

             Action值                                                說明

 

      ACTION_STATE_CHANGED                    藍牙狀態值發生改變

      ACTION_SCAN_MODE_CHANGED         藍牙掃描狀態(SCAN_MODE)發生改變

      ACTION_DISCOVERY_STARTED             藍牙掃描過程開始

      ACTION_DISCOVERY_FINISHED             藍牙掃描過程結束

      ACTION_LOCAL_NAME_CHANGED        藍牙設備Name發生改變

      ACTION_REQUEST_DISCOVERABLE       請求用戶選擇是否使該藍牙能被掃描

                PS:如果藍牙沒有開啟,用戶點擊確定后,會首先開啟藍牙,繼而設置藍牙能被掃描。

      ACTION_REQUEST_ENABLE                  請求用戶選擇是否打開藍牙

 

      ACTION_FOUND  (該常量字段位於BluetoothDevice類中)

                說明:藍牙掃描時,掃描到任一遠程藍牙設備時,會發送此廣播。

 

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {//開始掃描藍牙時候的廣播
              mDeviceList.clear();
               mAdapter.notifyDataSetChanged();
            }
            if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {   //這個廣播是掃描結束,藍牙發送的廣播
                if (progressDialog!=null){
                    progressDialog.cancel();
                    progressDialog=null;
                }
               showToast("搜素完成");
            }
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {   //當掃描到藍牙設備時,會發送這個廣播
               mDeviceList.add((BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
                mAdapter.notifyDataSetChanged();

               
            }
            if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {  //藍牙掃描狀態(SCAN_MODE)發生改變
                if (intent.getIntExtra("android.bluetooth.adapter.extra.SCAN_MODE", 0) == 23) {

                }
            }
            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {  //綁定時候的廣播
                BluetoothDevice remoteDevice = (BluetoothDevice) intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
                if (remoteDevice == null) {
                   showToast("no device");
                    return;
                }
                int status = intent.getIntExtra("android.bluetooth.device.extra.BOND_STATE", 0);
                if (status == 12) {
                   showToast("配對完成 " + remoteDevice.getName());
                    blueToothUtils.searchDevices();
                    showToast("刷新列表中 ");
                } else if (status == 11) {
                  showToast("正在配對 " + remoteDevice.getName());
                } else if (status == 10) {
                   showToast("配對失敗 " + remoteDevice.getName());
                }
            }
        }
    };

//設置要監聽的廣播。
void initView(){
 
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
mContext.registerReceiver(mReceiver, filter);
}
 

上面的設置完成以后

編寫一個藍牙工具類進行使用。方便以后的開發。

在一開始。網上找了一些藍牙的操作工具類。但是多多少少都有寫瑕疵。

大多數都是2個手機通信。無法和藍牙單片機模塊通信。

具體的藍牙操作類如下,這個工具類都是我在網上的大多數工具類中攢在一起的。里面有些方法也沒用。我也就不刪了。在接收數據的時候。如果是單片機發過來的話,數據會接收不完全。這里,將原來類方法更改了一下。、大家在接收數據時,盡量選擇一個用不到的數字或者字母等,來當做結束位。進行判斷、工具類里面的注釋基本都有。

在網上找資料時,發現2個工具類,一個如下,看着比較簡單,大家容易懂,還有一個。都是英文,后面翻譯了一下,也放在文章最后吧。其實思路都一樣。喜歡那個,用那個

工具類如下:

public class BlueToothUtils {
    private static final String TAG = "BlueToothUtils";
    private Context mContext;
    public static BlueToothUtils sInstance;
    private BluetoothAdapter mBA;
    private SharedPreferences sp;
    // UUID.randomUUID()隨機獲取UUID
    private final UUID MY_UUID = UUID
            .fromString("00001101-0000-1000-8000-00805F9B34FB");
    // 連接對象的名稱
    private final String NAME = "Chaoba";

    // 這里本身即是服務端也是客戶端,需要如下類
    private BluetoothSocket mSocket;
    private BluetoothDevice mOldDevice;
    private BluetoothDevice mCurDevice;
    // 輸出流_客戶端需要往服務端輸出
    private OutputStream os;
    private InputStream inputStream;
    //線程類的實例
    private AcceptThread ac;
    private Handler mhandler;
    private Handler handler2;

    private BlueToothUtils.Readtask readtask;

    public static synchronized BlueToothUtils getInstance() {
        if (sInstance == null) {
            sInstance = new BlueToothUtils();
        }
        return sInstance;
    }

    public BlueToothUtils() {
        mBA = BluetoothAdapter.getDefaultAdapter();
        ac = new AcceptThread();
    }

    public void setContext(Context context) {
        this.mContext = context;
    }

    public void setHandler(Handler handler){
        this.mhandler=handler;
    }
    public void setHandler2(Handler handler2){
        this.handler2=handler2;
    }
    public BluetoothAdapter getBA() {
        return mBA;
    }

    public AcceptThread getAc() {
        return ac;
    }

    public BluetoothDevice getCurDevice() {
        return mCurDevice;
    }

    /**
     * 判斷是否打開藍牙
     *
     * @return
     */
    public boolean isEnabled() {
        if (mBA.isEnabled()) {
            return true;
        }
        return false;
    }

    /**
     * 搜索設備
     */
    public void searchDevices() {
        // 判斷是否在搜索,如果在搜索,就取消搜索
        if (mBA.isDiscovering()) {
            mBA.cancelDiscovery();
        }
        // 開始搜索
        mBA.startDiscovery();
        Log.e(TAG, "正在搜索...");
    }

    /**
     * 獲取已經配對的設備
     *
     * @return
     */
    public List<BluetoothDevice> getBondedDevices() {
        List<BluetoothDevice> devices = new ArrayList<>();
        Set<BluetoothDevice> pairedDevices = mBA.getBondedDevices();
        // 判斷是否有配對過的設備
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                devices.add(device);
                Log.e(TAG, "BondedDevice:" + device.getName());
            }
        }
        return devices;
    }

    /**
     * 與設備配對
     *
     * @param device
     */
    public void createBond(BluetoothDevice device) {
        try {
            Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
            createBondMethod.invoke(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 與設備解除配對
     *
     * @param device
     */
    public void removeBond(BluetoothDevice device) {
        try {
            Method removeBondMethod = device.getClass().getMethod("removeBond");
            removeBondMethod.invoke(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param device
     * @param str  設置PIN碼
     * @return
     */
    public boolean setPin(BluetoothDevice device, String str) {
        try {
            Method removeBondMethod = device.getClass().getDeclaredMethod("setPin",
                    new Class[]{byte[].class});
            Boolean returnValue = (Boolean) removeBondMethod.invoke(device,
                    new Object[]{str.getBytes()});
            Log.e("returnValue", "" + returnValue);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 取消用戶輸入
     */
    public boolean cancelPairingUserInput(BluetoothDevice device) {
        Boolean returnValue = false;
        try {
            Method createBondMethod = device.getClass().getMethod("cancelPairingUserInput");
            returnValue = (Boolean) createBondMethod.invoke(device);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // cancelBondProcess()
        return returnValue.booleanValue();
    }

    /**
     * 取消配對
     */
    public boolean cancelBondProcess(BluetoothDevice device) {
        Boolean returnValue = null;
        try {
            Method createBondMethod = device.getClass().getMethod("cancelBondProcess");
            returnValue = (Boolean) createBondMethod.invoke(device);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return returnValue.booleanValue();
    }

    /**
     * @param strAddr
     * @param strPsw
     * @return
     */
    public boolean pair(String strAddr, String strPsw) {
        boolean result = false;
        mBA.cancelDiscovery();

        if (!mBA.isEnabled()) {
            mBA.enable();
        }

        if (!BluetoothAdapter.checkBluetoothAddress(strAddr)) { // 檢查藍牙地址是否有效
            Log.d("mylog", "devAdd un effient!");
        }

        BluetoothDevice device = mBA.getRemoteDevice(strAddr);
        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
            Log.d("mylog", "NOT BOND_BONDED");
            try {
                setPin(device, strPsw); // 手機和藍牙采集器配對
                createBond(device);
                result = true;
            } catch (Exception e) {
                Log.d("mylog", "setPiN failed!");
                e.printStackTrace();
            } //

        } else {
            Log.d("mylog", "HAS BOND_BONDED");
            try {
                createBond(device);
                setPin(device, strPsw); // 手機和藍牙采集器配對
                createBond(device);
                result = true;
            } catch (Exception e) {
                Log.d("mylog", "setPiN failed!");
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 獲取device.getClass()這個類中的所有Method
     *
     * @param clsShow
     */
    public void printAllInform(Class clsShow) {
        try {
            // 取得所有方法
            Method[] hideMethod = clsShow.getMethods();
            int i = 0;
            for (; i < hideMethod.length; i++) {
                Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i);
            }
            // 取得所有常量
            Field[] allFields = clsShow.getFields();
            for (i = 0; i < allFields.length; i++) {
                Log.e("Field name", allFields[i].getName());
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 打開藍牙
     */
    public void openBlueTooth() {
        if (!mBA.isEnabled()) {
            // 彈出對話框提示用戶是后打開
            /*Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 1);*/
            // 不做提示,強行打開
            mBA.enable();
            showToast("打開藍牙");
        } else {
            showToast("藍牙已打開");
        }
    }

    /**
     * 關閉藍牙
     */
    public void closeBlueTooth() {
        mBA.disable();
        showToast("關閉藍牙");
    }

    /**
     * 彈出Toast窗口
     *
     * @param message
     */
    private void showToast(String message) {
        if (mContext != null) {
            Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
        } else {
            Log.e(TAG, "message:" + message);
        }
    }

    /**
     * 主動連接藍牙
     *
     * @param device
     */
    public void connectDevice(BluetoothDevice device) {
        // 判斷是否在搜索,如果在搜索,就取消搜索
        if (mBA.isDiscovering()) {
            mBA.cancelDiscovery();
        }
        try {
            // 獲得遠程設備
            if (mCurDevice == null || mCurDevice != mOldDevice) {
                mCurDevice = mBA.getRemoteDevice(device.getAddress());
                mOldDevice = mCurDevice;
                Log.e(TAG, "device:" + mCurDevice);
//                sp.edit().putString("device","device:"+mCurDevice).commit();
                mSocket = mCurDevice.createRfcommSocketToServiceRecord(MY_UUID);
                // 連接
//                mSocket.connect();
//                boolean connected = mSocket.isConnected();
//                if (connected){
//
//                    // 獲得輸出流
//                    os = mSocket.getOutputStream();
//                    inputStream=mSocket.getInputStream();
//                    while (true){
//                        readDataFromServer();
//                    }
//                }


                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            mSocket.connect();
                            os = mSocket.getOutputStream();
                            mhandler.sendEmptyMessage(10);
                            readtask = new BlueToothUtils.Readtask();  //連接成功后開啟讀取數據的線程
                            readtask.start();
                            mContext.getSharedPreferences("demo",Context.MODE_PRIVATE).edit().putString("device","已連接").commit();
                        } catch (IOException e) {
                            mhandler.sendEmptyMessage(11);
                            e.printStackTrace();
                        }
                    }
                }).start();

            }
            // 如果成功獲得輸出流

        } catch (IOException e) {
            e.printStackTrace();
            mhandler.sendEmptyMessage(11);

        }





    }


    public static final int CONNECT_FAILED=1;
    public static final int CONNECT_SUCCESS=5;
    public  static final int READ_FAILED=2;
    public static final int WRITE_FAILED=3;
    public  static final int DATA=4;
    private boolean isConnect=false;

    /**
     *開辟連接線程任務
     */
    public void connectTow(final BluetoothDevice device){
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                BluetoothSocket tmp = null;
                Method method;
                try {
                    method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                    tmp = (BluetoothSocket) method.invoke(device, 1);
                } catch (Exception e) {
//                    setState(CONNECT_FAILED);
                    Log.e("TAG", e.toString());
                }
                mSocket = tmp;
                try {
                    mSocket.connect();
                    isConnect = true;
//                    setState(CONNECT_SUCCESS);
                   readtask = new BlueToothUtils.Readtask();  //連接成功后開啟讀取數據的線程
                    readtask.start();
                } catch (Exception e) {

                    Log.e("TAG", e.toString());
                }
            }
        });
        new Thread(thread).start();
    }
    /**
     *開辟線程讀任務
     */
    public class Readtask extends Thread{
        @Override
        public void run(){
//            byte[] buffer = new byte[9999];
//            int bytes;
//            InputStream inputStream ;   //建立輸入流讀取數據
//            while (true) {
//                try {
//                    inputStream = mSocket.getInputStream();
//                    if ((bytes = inputStream.read(buffer)) > 0) {
//                        byte[] buf_data= new byte[bytes];
//                        for (int i = 0; i < bytes; i++) {
//                            buf_data[i] = buffer[i];
//                        }
//                        String s = new String(buf_data);
//
//                        setState(1,s);
//
//                    }
//                } catch (IOException e) {
//
//                    Log.e("TAG", e.toString());
//                    break;
//                }
//            }



            byte[] tt = new byte[100];
            try {
                int ch;
                inputStream = mSocket.getInputStream();

                int i;
                while (true) {
                    synchronized (this) {
                     i=0;
                        while ((ch=inputStream.read())!='#'){
                            if (ch!=-1){
                                tt[i]=(byte)ch;
                                i++;
                            }


                        }

                        if (tt.length > 0) {
                            String s = new String(tt, "GBK");
                        System.out.println(s);
                            setState(1,s);
                        }else {
                            System.out.println(111);
                        }
                    }
                }


            } catch (IOException e) {
                e.printStackTrace();
                Message message=new Message();
                message.obj="連接已斷開,請重新連接";
                handler.sendMessage(message);
            }



            if (mSocket != null) {
                try {
                    mSocket.close();
                } catch (IOException e) {
                    Log.e("TAG", e.toString());
                }
            }
        }
        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
    /**
     *開辟線程寫任務
     */
    public  class WriteTask extends Thread{
        private String srt;
        public  WriteTask(String str){
            this.srt=str;
        }
        @Override
        public void run(){
            OutputStream outputStream=null;
            byte[] st=srt.getBytes();
            try{
                outputStream=mSocket.getOutputStream();
                outputStream.write(st);
            }catch (Exception e){

                e.printStackTrace();
            }
        }

    }


    private void setState(int mes,String str){
        Message message=new Message();
        message.what=mes;
        message.obj=str;
        handler2.sendMessage(message);

    }







    /**
     * 傳輸數據
     *
     * @param message
     */
    public void write(String message) {
        try {
            if (os != null) {
                os.write(message.getBytes("GBK"));
            }
            Log.e(TAG, "write:" + message);
            handler2.sendEmptyMessage(3);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * Stop all threads
     */
    public synchronized void stops() {

        if (readtask != null) {readtask.cancel(); readtask = null;}
            Message message=new Message();
        message.obj="關閉所有線程";
        handler.sendMessage(message);
    }


    public void initSP(){
        sp=mContext.getSharedPreferences("demo",Context.MODE_PRIVATE);
    }

    // 服務端,需要監聽客戶端的線程類
    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            showToast(String.valueOf(msg.obj));
            Log.e(TAG, "服務端:" + msg.obj);
            super.handleMessage(msg);
        }
    };


    // 線程服務類
    public class AcceptThread extends Thread {
        private BluetoothServerSocket serverSocket;
        private BluetoothSocket socket;
        // 輸入 輸出流
        private OutputStream os;
        private InputStream is;

        public AcceptThread() {
            try {
                serverSocket = mBA.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            // 截獲客戶端的藍牙消息
            try {
                socket = serverSocket.accept(); // 如果阻塞了,就會一直停留在這里
                is = socket.getInputStream();
                os = socket.getOutputStream();
                while (true) {
                    synchronized (this) {
                        byte[] tt = new byte[is.available()];
                        if (tt.length > 0) {
                            is.read(tt, 0, tt.length);
                            Message msg = new Message();
                            msg.obj = new String(tt, "GBK");
                            Log.e(TAG, "客戶端:" + msg.obj);
                            handler.sendMessage(msg);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}

 

第二個工具類

/**
 *建立和管理與其他設備的BT連接。

 *它有一個線程來偵聽傳入的連接,一個線程

 *用於與設備連接,以及用於執行數據的線程

 *連接時的傳輸。
 */
public class BTService {

    // 表示當前連接狀態的常量
    public static final int STATE_NONE = 0;         // 我們什么也不做
    public static final int STATE_LISTEN = 1;       // 現在監聽傳入的連接
    public static final int STATE_CONNECTING = 2;   // 現在啟動輸出連接
    public static final int STATE_CONNECTED = 3;    // 現在連接到遠程設備
    private static final String TAG = "BTConnection";
    // 創建服務器套接字時SDP記錄的名稱
    private static final String MY_NAME = "BTConnection";

//引用:[來自Android SDK文檔]

//如果您正在連接藍牙串行板,則嘗試使用眾所周知的

//SPP UUID 000 000 110~00 0 0 0 0 0 0 0 0 0 0 0 5 5 F9B34 FB。

//    但是,如果您正在連接Android對等體,那么請生成您自己的
//
///獨特的UUID。
    private static final UUID MY_UUID =
            UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    // 成員字段
    private final BluetoothAdapter mAdapter;
    private final Handler mHandler;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnThread;
    private ConnectedThread mConnectedThread;
    private int mState;
    private final Context mContext;
    public static BTService sInstance;
    /**
     * Constructor. Prepares a new BT session.
     *
     * @param handler A Handler to send message back to the UI Activity.
     *                構造函數。准備新的BT會話。 * * @param handler一個Handler,用於將消息發送回UI Activity。
     */
    public BTService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
        mContext = context;
    }



    /**
     * 判斷是否打開藍牙
     *
     * @return
     */
    public boolean isEnabled() {
        if (mAdapter.isEnabled()) {
            return true;
        }
        return false;
    }

    /**
     * 搜索設備
     */
    public void searchDevices() {
        // 判斷是否在搜索,如果在搜索,就取消搜索
        if (mAdapter.isDiscovering()) {
            mAdapter.cancelDiscovery();
        }
        // 開始搜索
        mAdapter.startDiscovery();
        Log.e(TAG, "正在搜索...");
    }

    /**
     * 獲取已經配對的設備
     *
     * @return
     */
    public List<BluetoothDevice> getBondedDevices() {
        List<BluetoothDevice> devices = new ArrayList<>();
        Set<BluetoothDevice> pairedDevices = mAdapter.getBondedDevices();
        // 判斷是否有配對過的設備
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                devices.add(device);
                Log.e(TAG, "BondedDevice:" + device.getName());
            }
        }
        return devices;
    }

    /**
     * 與設備配對
     *
     * @param device
     */
    public void createBond(BluetoothDevice device) {
        try {
            Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
            createBondMethod.invoke(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 與設備解除配對
     *
     * @param device
     */
    public void removeBond(BluetoothDevice device) {
        try {
            Method removeBondMethod = device.getClass().getMethod("removeBond");
            removeBondMethod.invoke(device);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param device
     * @param str  設置PIN碼
     * @return
     */
    public boolean setPin(BluetoothDevice device, String str) {
        try {
            Method removeBondMethod = device.getClass().getDeclaredMethod("setPin",
                    new Class[]{byte[].class});
            Boolean returnValue = (Boolean) removeBondMethod.invoke(device,
                    new Object[]{str.getBytes()});
            Log.e("returnValue", "" + returnValue);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 取消用戶輸入
     */
    public boolean cancelPairingUserInput(BluetoothDevice device) {
        Boolean returnValue = false;
        try {
            Method createBondMethod = device.getClass().getMethod("cancelPairingUserInput");
            returnValue = (Boolean) createBondMethod.invoke(device);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // cancelBondProcess()
        return returnValue.booleanValue();
    }

    /**
     * 取消配對
     */
    public boolean cancelBondProcess(BluetoothDevice device) {
        Boolean returnValue = null;
        try {
            Method createBondMethod = device.getClass().getMethod("cancelBondProcess");
            returnValue = (Boolean) createBondMethod.invoke(device);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return returnValue.booleanValue();
    }

    /**
     * @param strAddr
     * @param strPsw
     * @return
     */
    public boolean pair(String strAddr, String strPsw) {
        boolean result = false;
        mAdapter.cancelDiscovery();

        if (!mAdapter.isEnabled()) {
            mAdapter.enable();
        }

        if (!BluetoothAdapter.checkBluetoothAddress(strAddr)) { // 檢查藍牙地址是否有效
            Log.d("mylog", "devAdd un effient!");
        }

        BluetoothDevice device = mAdapter.getRemoteDevice(strAddr);
        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
            Log.d("mylog", "NOT BOND_BONDED");
            try {
                setPin(device, strPsw); // 手機和藍牙采集器配對
                createBond(device);
                result = true;
            } catch (Exception e) {
                Log.d("mylog", "setPiN failed!");
                e.printStackTrace();
            } //

        } else {
            Log.d("mylog", "HAS BOND_BONDED");
            try {
                createBond(device);
                setPin(device, strPsw); // 手機和藍牙采集器配對
                createBond(device);
                result = true;
            } catch (Exception e) {
                Log.d("mylog", "setPiN failed!");
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 獲取device.getClass()這個類中的所有Method
     *
     * @param clsShow
     */
    public void printAllInform(Class clsShow) {
        try {
            // 取得所有方法
            Method[] hideMethod = clsShow.getMethods();
            int i = 0;
            for (; i < hideMethod.length; i++) {
                Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i);
            }
            // 取得所有常量
            Field[] allFields = clsShow.getFields();
            for (i = 0; i < allFields.length; i++) {
                Log.e("Field name", allFields[i].getName());
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 打開藍牙
     */
    public void openBlueTooth() {
        if (!mAdapter.isEnabled()) {
            // 彈出對話框提示用戶是后打開
            /*Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 1);*/
            // 不做提示,強行打開
            mAdapter.enable();
            showToast("打開藍牙");
        } else {
            showToast("藍牙已打開");
        }
    }

    /**
     * 關閉藍牙
     */
    public void closeBlueTooth() {
        mAdapter.disable();
        showToast("關閉藍牙");
    }

    /**
     * 彈出Toast窗口
     *
     * @param message
     */
    private void showToast(String message) {
        if (mContext != null) {
            Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
        } else {
            Log.e(TAG, "message:" + message);
        }
    }





    public static synchronized BTService getInstance(Context context, Handler handler) {
        if (sInstance == null) {
            sInstance = new BTService(context,handler);
        }
        return sInstance;
    }


    public BluetoothAdapter getBA() {
        return mAdapter;
    }
    /**
     * Return the current connection state.
     *
     * @return mState current connection state
     * 返回當前連接狀態。 * * @return mState當前連接狀態
     */
    public synchronized int getState() {
        return mState;
    }

    /**
     * Set the current state of BT connection.
     *
     * @param state An integer defining the current connection state
     *
     *    *設置BT連接的當前狀態。 * * @param state定義當前連接狀態的整數
     */
    private synchronized void setState(int state) {
        Log.d(TAG, "setState() " + mState + "-> " + state);
        mState = state;

        // Give the new state to the Handler so the UI Activity can update
        //將新狀態提供給處理程序,以便UI活動可以更新
        mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }

    /**
     * Start the BT service. Specifically start AcceptThread to begin a
     * session in listening (server) mode. Called by the Activity onResume()
     * *啟動BT服務。具體來說,啟動AcceptThread以在偵聽(服務器)模式下開始*會話。由Activity onResume()調用
     */
    public synchronized void start() {
        Log.d(TAG, "start");

        // Cancel any thread attempting to make a connection
        //取消任何嘗試建立連接的線程
        if (mConnThread != null) {
            mConnThread.cancel();
            mConnThread = null;
        }

        // Cancel any thread currently running a connection
        //取消當前正在運行連接的任何線程
        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        setState(STATE_LISTEN);

        // Start the thread to listen on a BluetoothServerSocket
        //啟動線程以偵聽BluetoothServerSocket
        if (mAcceptThread == null) {
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
    }

    /**
     * Start the ConnThread to initiate a connection to a remote device.
     *啟動ConnThread以啟動與遠程設備的連接。
     * @param device The BluetoothDevice to connect
     */
    public synchronized void connect(BluetoothDevice device) {
        Log.d(TAG, "Connect to: " + device);

        // Cancel any thread attempting to make a connection
        //取消任何嘗試建立連接的線程
        if (mState == STATE_CONNECTING) {
            if (mConnThread != null) {
                mConnThread.cancel();
                mConnThread = null;
            }
        }
        // Cancel any thread currently running a connection
        //取消當前正在運行連接的任何線程
        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
        // Start the thread to connect with the given device
        //啟動線程以連接給定設備
        mConnThread = new ConnectThread(device);
        mConnThread.start();
        setState(STATE_CONNECTING);
    }

    /**
     * 啟動ConnectedThread以開始管理藍牙連接。
     *
     * @param socket 連接所在的BluetoothSocket
     * @param device 已連接的BluetoothDevice
     */
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
        Log.d(TAG, "Connected");

        // 取消完成連接的線程
        if (mConnThread != null) {
            mConnThread.cancel();
            mConnThread = null;
        }
       //取消當前正在運行連接的任何線程
        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
       //取消接受線程,因為我們只想連接到一個設備
        if (mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }

      //啟動線程來管理連接並執行傳輸
        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();

        // 將已連接設備的名稱發送回UI活動
        Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(Constants.DEVICE_NAME, device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        setState(STATE_CONNECTED);
    }


    /**
     * 停止所有線程。
     */
    public synchronized void stop() {
        Log.d(TAG, "stop");

        if (mConnThread != null) {
            mConnThread.cancel();
            mConnThread = null;
        }
        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
        if (mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        setState(STATE_NONE);
    }

    /**
     * 以不同步的方式寫入ConnectedThread。
     *
     * @param content 要寫入的字節
     * @see
     */
    public void write(String content) {
     //創建臨時對象
        ConnectedThread r;
      //同步ConnectedThread的副本
        synchronized (this) {
            if (mState != STATE_CONNECTED) {
                Log.d(TAG, "State: " + getState());
                return;
            }
            r = mConnectedThread;
        }
       //執行寫入不同步
        r.write(content);
    }

    /**
     * 指示連接嘗試失敗並通知UI活動。
     */
    private void connectionError(String errMsg) {
        Log.e(TAG, "Connection Error:" + errMsg);
        // 將失敗消息發送回活動
        Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(Constants.TOAST, errMsg);
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        // 啟動服務以重新啟動偵聽模式
        BTService.this.start();
    }


    /**
   *此線程在偵聽傳入連接時運行。它表現得很好
     *像服務器端客戶端。它會一直運行,直到接受連接
     *(或直到取消)。
     */
    private class AcceptThread extends Thread {
        private final BluetoothServerSocket mmServerSocket;

        public AcceptThread() {
           //使用稍后分配給mmServerSocket的臨時對象
            //因為mmServerSocket是最終的
            BluetoothServerSocket tmp = null;

            try {
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(MY_NAME, MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "套接字聽不通", e);
            }
            mmServerSocket = tmp;
        }

        public void run() {
            Log.d(TAG, "套接字開始");

            BluetoothSocket socket = null;

            // Listen to the server socket if we're not connected
            while (mState != STATE_CONNECTED) {
                try {
                   //這是一個阻止調用,只會返回
                    //成功連接或異常
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                    Log.e(TAG, "套接字accept()失敗", e);
                    break;
                }

            //如果接受了連接
                if (socket != null) {
                    synchronized (BTService.this) {
                        switch (mState) {
                            case STATE_LISTEN:
                            case STATE_CONNECTING:
                               //情況正常啟動連接的線程。
                                connected(socket, socket.getRemoteDevice());
                                break;
                            case STATE_NONE:
                            case STATE_CONNECTED:
                             //未准備好或已連接。終止新套接字。
                                try {
                                    socket.close();
                                } catch (IOException e) {
                                    Log.e(TAG, "無法關閉不需要的套接字", e);
                                }
                                break;
                        }
                    }
                }
            }
        }

        public void cancel() {
            Log.d(TAG, "套接字取消");
            try {
                mmServerSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "服務器的套接字close()失敗", e);
            }
        }
    }

    /***此線程在嘗試進行傳出連接時運行
     *帶有設備。它直接通過;連接
     *成功或失敗。
     */
    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        private ConnectThread(BluetoothDevice device) {
            mmDevice = device;
            BluetoothSocket tmp = null;

         //獲取與之連接的BluetoothSocket
            //給出了BluetoothDevice
            try {
//                device.fetchUuidsWithSdp();
//                ParcelUuid[] uuids = device.getUuids();
//                for (ParcelUuid u : uuids) {
//                    Log.d(TAG, u.getUuid().toString());
//                }
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "Socket create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            try {
                mmSocket.connect();
            } catch (IOException e) {
                e.printStackTrace();
                try {
                    mmSocket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                connectionError("連接失敗");
                return;
            }

           //重置ConnectThread,因為我們已經完成了
            synchronized (BTService.this) {
                mConnThread = null;
            }

           //啟動連接的線程
            connected(mmSocket, mmDevice);
        }

        public void cancel() {
            Log.d(TAG, "Socket cancel");
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Socket close() of server failed", e);
            }
        }
    }

    /**
    *此線程在與遠程設備連接期間運行。
     *它處理所有傳入和傳出傳輸。
     */
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        private ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            //獲取BluetoothSocket輸入和輸出流
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.d(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[512];
            byte[] ret = null;

           //連接時繼續收聽inputStream
            while (true) {
                try {
                    //從InputStream中讀取
                    int bytes = mmInStream.read(buffer);
                    Log.e(TAG, "length: " + bytes);

                    for (int i = 0; i < bytes; i++) {
                        if ((buffer[i] & 0xFF) == 255) {
                            ret = Arrays.copyOfRange(buffer, 0, i + 1);
                            break;
                        }
                    }
                    Log.e(TAG, "data: " + ret);
                   //將獲取的字節發送到UI活動
                    mHandler.obtainMessage(Constants.MESSAGE_READ, -1, -1, ret).sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionError("連接失敗");
                   //啟動服務以重新啟動偵聽模式
                    BTService.this.start();
                    break;
                }
            }
        }

        /**
         * 寫入已連接的OutStream。
         *
         * @param content The bytes to write
         */
        public void write(String content) {
            try {
                mmOutStream.write(content.getBytes());
                // 將發送的消息共享回UI活動
                mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, content).sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "E寫入期間的xception", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "connect()的連接套接字失敗", e);
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM