package com.eztlib; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.UUID; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import com.ectrip.cyt.config.MyApp; import com.ectrip.cyt.utils.LogUtil; /** * 这个类处理所有工作的设置和管理蓝牙连接其他设备 它有一个线程,监听传入连接 一个线程用于连接设备和一个线程用于执行数据传输连接时 * */ public class BluetoothService { static { try { System.loadLibrary("EZTLIB"); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } } /// /// 端口发送数据 /// /// 要写入的数据 /// 数据长度 /// 返回写入的数据长度 public static native int BluSendBytes(byte[] pDataIn, int Inlen); /// /// 端口读取数据 /// /// 返回数据 /// 想要读取长度 /// 返回读取到的数据长 public static native int BluReadBytes(byte[] pDataOut, int len); //从BluetoothService处理程序发送消息类型 public static final int MESSAGE_STATE_CHANGE=1; public static final int MESSAGE_READ=2; public static final int MESSAGE_WRITE=3; public static final int MESSAGE_DEVICE_NAME=4; public static final int MESSAGE_TOAST=5; // BluetoothService收到的处理程序关键的名字 public static final String DEVICE_NAME="device_name"; public static final String TOAST="toast"; public static final String TAG = "BluetoothService"; public static final boolean LogEnablD = false; // 在创建服务器套接字记录SDP的名字 private static final String NAME = "EZTPrinter"; // 给这个应用程序设置一个独特的UUID private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 当前连接状态的常量 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; // 连接到一个远程设备 public static final int STATE_FAILL=8;//失败 private final BluetoothAdapter mAdapter; private final Handler mHandler; // private AcceptThread mAcceptThread= null; private ConnectThread mConnectThread= null; private static ConnectedThread mConnectedThread= null; private static int mState= STATE_NONE; private static boolean stop=false; //构造函数。准备一个新的BTPrinter会话 ontext UI活动上下文 handler 处理程序发送消息发送回UI活动 public BluetoothService(Context context, Handler handler) { stop=true; mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; try { COMPacket.COMClose(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } Thread thread=new Thread(new Runnable() { byte[] buffer = new byte[4096]; int bytes; @Override public void run() { while (!stop) { if ((mState==BluetoothService.STATE_CONNECTED) && (mConnectedThread != null)) { bytes=BluReadBytes(buffer,buffer.length); if(bytes>0) { mConnectedThread.write(buffer, 0, bytes); } } } } }); stop=false; thread.start(); } //设置当前状态的连接 state 定义当前的连接状态 private synchronized void setState(int state) { if (LogEnablD) {Log.d(TAG, "setState()" + mState + "->" + state);} mState = state; // 给新状态Handler让UI可以更新 mHandler.obtainMessage(MESSAGE_STATE_CHANGE, state,-1).sendToTarget(); } //返回当前的连接状态 public synchronized int getState() {return mState;} //启动服务。特别是在聆听(服务器)模式开始AcceptThread 会话,调用活动onResume() public synchronized void start() { if (LogEnablD){Log.d(TAG, "start");} // 取消任何线程试图连接 if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } // 在运行一个连接时取消任何线程 if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // 启动线程来监听BluetoothServerSocket // if (mAcceptThread == null) { // mAcceptThread = new AcceptThread(); // mAcceptThread.start(); // } setState(STATE_LISTEN); try { COMPacket.COMClose(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } } //启动ConnectThread发起连接到一个远程设备。 device BluetoothDevice的连接 public synchronized void connect(BluetoothDevice device) { if (LogEnablD){LogUtil.d(TAG, "connect to:" + device);} // 取消任何线程试图连接 if (mState == STATE_CONNECTING) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } } // 正在运行一个连接时取消任何线程 if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // 启动线程与给定的设备 mConnectThread = new ConnectThread(device); mConnectThread.start(); setState(STATE_CONNECTING); COMPacket.COMClose(); } //启动ConnectedThread开始管理一个蓝牙连接 //@param socket BluetoothSocket上的连接 //@param device 这个BluetoothDevice已经连接 public synchronized void connected(BluetoothSocket socket,BluetoothDevice device) { if (LogEnablD){LogUtil.d(TAG, "Connected");} // 取消线程完成连接 if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = 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(MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(DEVICE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); COMPacket.COMOpen("Bluetooth",0,0); } //停止所有的线程 public synchronized void stop() { if (LogEnablD){Log.d(TAG, "stop");} setState(STATE_NONE); if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // if (mAcceptThread != null) { // mAcceptThread.cancel(); // mAcceptThread = null; // } COMPacket.COMClose(); } //启动ConnectThread发起连接到一个远程设备 //@param device BluetoothDevice的连接 //连接请求失败并通知UI活动 private void connectionFailed() { setState(STATE_FAILL); // 一条失败消息发送回活动 MyApp.getInstance().setBluConnection(false); Message msg = mHandler.obtainMessage(MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(TOAST, "不能连接到设备!"); bundle.putBoolean("sucess", false); msg.setData(bundle); mHandler.sendMessage(msg); } //表示这个连接丢失并通知UI活动。 private void connectionLost() { // 一条失败消息发送给Activity Message msg = mHandler.obtainMessage(MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(TOAST, "已断开与打印机的连接!"); msg.setData(bundle); mHandler.sendMessage(msg); } //启动ConnectedThread开始管理一个蓝牙连接 socket BluetoothSocket上的连接 device //装置的BluetoothDevice已经连接 //这个线程运行试图使一个外向连接一个设备。它运行直通要么连接成功要么失败。 private class ConnectThread extends Thread { private BluetoothSocket mmSocket; private BluetoothDevice mmDevice; @SuppressLint("NewApi") public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; // 为一个连接的BluetoothDevice得到一个BluetoothSocket try { Method m = null; try { m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); } catch (NoSuchMethodException e) { e.printStackTrace(); } try { tmp = (BluetoothSocket) m.invoke(device, 1); tmp.connect(); MyApp.getInstance().setBluConnection(true); } catch (IllegalAccessException e) { e.printStackTrace(); connectionFailed(); return; } catch (IllegalArgumentException e) { e.printStackTrace(); connectionFailed(); return; } catch (Exception e){ e.printStackTrace(); connectionFailed(); return; } } catch (Exception e) { connectionFailed(); Log.e(TAG, "create failed"+e); return; } mmSocket = tmp; } public void run() { LogUtil.i(TAG, "BEFIN mConnectThrread"); setName("ConnectThread"); mAdapter.cancelDiscovery(); // 让BluetoothSocket的连接 try { // 一个阻塞调用返回成功连接或一个例外 if(!MyApp.getInstance().isBluConnection()){ if(mmSocket!=null){ mmSocket.connect(); }else{ setState(STATE_FAILL); return; } if(mmSocket==null){ setState(STATE_FAILL); return; } } } catch (IOException e) { e.printStackTrace(); // 关闭socket connectionFailed(); try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() socket during connection failure", e2); } // 启动服务到重启的听力模式 // BluetoothService.this.start(); return; } if(MyApp.getInstance().isBluConnection()){ // 重置ConnectThread synchronized (BluetoothService.this) { mConnectThread = null; } // 启动连接的线程 connected(mmSocket, mmDevice); } } public void cancel() { try { mmDevice.describeContents(); if(mmSocket!=null){ mmSocket.close(); mmSocket=null; } } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } //这个线程运行在连接一个远程的设备上 它处理所有传入和传出的传输。 private class ConnectedThread extends Thread { private BluetoothSocket mmSocket; private InputStream mmInStream; private OutputStream mmOutStream; boolean stop=false; public 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.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[4096]; int bytes; while (!stop) { try { // 从InputStream中阅读 bytes = mmInStream.read(buffer); BluSendBytes(buffer,bytes); //mHandler.obtainMessage(MainActivity.MESSAGE_READ,bytes, -1, buffer).sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); connectionLost(); if (mState != STATE_NONE) { BluetoothService.this.start(); }else{ connectionLost(); } break; } } } //OutStream写入连接 //@param buffer 写的字节 public void write(byte[] buffer,int offset, int count) { try { mmOutStream.write(buffer,offset,count); // 分享所发送的消息回到UI的Activity //mHandler.obtainMessage(MESSAGE_WRITE, -1, -1,buffer).sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmInStream.close(); mmInStream=null; mmOutStream.close(); mmOutStream=null; stop=true; mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } // 与设备配对 参考源码:platform/packages/apps/Settings.git // \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java public static boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception { Method createBondMethod = btClass.getMethod("createBond"); Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice); return returnValue.booleanValue(); } // 与设备解除配对 参考源码:platform/packages/apps/Settings.git // \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java public static boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception { Method removeBondMethod = btClass.getMethod("removeBond"); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice); return returnValue.booleanValue(); } }