Android蓝牙socket实现视频实时传输,以及图片和文本传输 |
您所在的位置:网站首页 › 蓝牙怎样传输视频 › Android蓝牙socket实现视频实时传输,以及图片和文本传输 |
目标
两台手机设备之间能够正常进行蓝牙配对(蓝牙模块儿和硬件挂钩,所以需要两台真机)
socket实现蓝牙文本传输
实现图片传输
实现实时视频传输 代码下载:https://download.csdn.net/download/m0_37781149/10434336 蓝牙传输注意事项 Bluetooth的MTU(最大传输单元)是20字节,即一次最多能发送20个字节,若超过20个字节,建议采用分包传输的方式。在传输图片和视频的时候处理方式是将图片转换成字节byte,并在图片前面添加一个头,加入相应的标志位,例如图片大小。然后在接受端进行整合,获取图片大小(字节长度),进行相应判断,整合成图片再显示。下面分模块儿讲解: 蓝牙扫描 通过注册广播来获取蓝牙列表,蓝牙连接状态发生改变时候系统都会发送相应广播,获取相应的蓝牙列表并添加到list中,显示出来 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //当发现蓝牙设备 if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { String strNoFound = getIntent().getStringExtra("no_devices_found"); if (strNoFound == null) strNoFound = "No devices found"; if (mPairedDevicesArrayAdapter.getItem(0).equals(strNoFound)) { mPairedDevicesArrayAdapter.remove(strNoFound); } mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); String strSelectDevice = getIntent().getStringExtra("select_device"); if (strSelectDevice == null) strSelectDevice = "Select a device to connect"; setTitle(strSelectDevice); } } }; //扫描蓝牙设备 private void doDiscovery() { mPairedDevicesArrayAdapter.clear(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } else { String strNoFound = getIntent().getStringExtra("no_devices_found"); if (strNoFound == null) strNoFound = "No devices found"; mPairedDevicesArrayAdapter.add(strNoFound); } String strScanning = getIntent().getStringExtra("scanning"); if (strScanning == null) strScanning = "Scanning for devices..."; setProgressBarIndeterminateVisibility(true); setTitle(strScanning); if (mBtAdapter.isDiscovering()) { mBtAdapter.cancelDiscovery(); } mBtAdapter.startDiscovery(); } 点击对应的条目可以回退到MainActivity,并将对应的mac地址携带回来,用于蓝牙配对连接 //携带蓝牙地址返回主界面 private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView av, View v, int arg2, long arg3) { if (mBtAdapter.isDiscovering()) mBtAdapter.cancelDiscovery(); String strNoFound = getIntent().getStringExtra("no_devices_found"); if (strNoFound == null) strNoFound = "No devices found"; if (!((TextView) v).getText().toString().equals(strNoFound)) { String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); Intent intent = new Intent(); intent.putExtra(BluetoothState.EXTRA_DEVICE_ADDRESS, address); setResult(Activity.RESULT_OK, intent); finish(); } } }; 蓝牙连接核心工具类BluetoothUtil,蓝牙状态BluetoothState和BluetoothService 蓝牙配对基本过程:在APP启动的时候,开启一个线程一直监听蓝牙的连接状态,这个子线程是启动时是死循环状态,在蓝牙连接成功时会停止,在蓝牙意外断开时候会重新处于监听状态 public void onStart() { super.onStart(); if (!mBt.isBluetoothEnabled()) { //打开蓝牙 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT); } else { if (!mBt.isServiceAvailable()) { //开启监听 mBt.setupService(); mBt.startService(BluetoothState.DEVICE_ANDROID); } } } public void setupService() { mChatService = new BluetoothService(mContext, mHandler); } public BluetoothService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = BluetoothState.STATE_NONE; mHandler = handler; } //开启蓝牙一直监听是否连接的状态 public void startService(boolean isAndroid) { if (mChatService != null) { if (mChatService.getState() == BluetoothState.STATE_NONE) { isServiceRunning = true; mChatService.start(isAndroid); BluetoothUtil.this.isAndroid = isAndroid; } } } //开启子线程 public synchronized void start(boolean isAndroid) { // Cancel any thread attempting to make a connection if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(BluetoothState.STATE_LISTEN); //开启子线程 if (mSecureAcceptThread == null) { mSecureAcceptThread = new AcceptThread(isAndroid); mSecureAcceptThread.start(); BluetoothService.this.isAndroid = isAndroid; } } //监听蓝牙连接的线程 private class AcceptThread extends Thread { private BluetoothServerSocket mmServerSocket; private String mSocketType; boolean isRunning = true; public AcceptThread(boolean isAndroid) { BluetoothServerSocket tmp = null; try { if (isAndroid) //获取蓝牙socket tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_ANDROID_DEVICE); else tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_OTHER_DEVICE); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { setName("AcceptThread" + mSocketType); BluetoothSocket socket = null; //死循环监听蓝牙连接状态,首次进入一定满足条件,蓝牙连上后,循环停止 while (mState != BluetoothState.STATE_CONNECTED && isRunning) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } if (socket != null) { synchronized (BluetoothService.this) { switch (mState) { case BluetoothState.STATE_LISTEN: case BluetoothState.STATE_CONNECTING: connected(socket, socket.getRemoteDevice(), mSocketType); break; case BluetoothState.STATE_NONE: case BluetoothState.STATE_CONNECTED: try { socket.close(); } catch (IOException e) { } break; } } } } } public void cancel() { try { mmServerSocket.close(); mmServerSocket = null; } catch (IOException e) { } } public void kill() { isRunning = false; } } 核心部分:蓝牙发送和接受数据,蓝牙发送数据处理过程,比如发送一张图片,肯定是大于20字节的,蓝牙是采用分包发送机制,在处理的时候,我们把图片转换成字节,并在图片前面添加一个头,这个头是固定字节的长度,不能太小,因为拍摄图片的时候,图片有大有小,避免和图面装换成字节后产生冲突。这个头里面主要携带两个信息,当然也可以是多个,自由定义。两个信息分别是,图片的大小,即字节长度length,还有一个是动作,例如传照片,传文本,实时视频传输,代码如下: //添加头发送数据 public void send(byte[] data, String str) { int length = data.length; byte[] length_b = null; try { length_b = intToByteArray(length); } catch (Exception e) { e.printStackTrace(); } if (length_b == null) return; //获得一个字节长度为14的byte数组 headInfoLength为14 byte[] headerInfo = new byte[headInfoLength]; //前六位添加012345的标志位 for (int i = 0; i < headInfoLength - 8; i++) { headerInfo[i] = (byte) i; } //7到10位添加图片大小的字节长度 for (int i = 0; i < 4; i++) { headerInfo[6 + i] = length_b[i]; } //11到14位添加动作信息 if (str.equals("text")) { for (int i = 0; i < 4; i++) { headerInfo[10 + i] = (byte) 0; } } else if (str.equals("photo")) { for (int i = 0; i < 4; i++) { headerInfo[10 + i] = (byte) 1; } } else if (str.equals("video")) { for (int i = 0; i < 4; i++) { headerInfo[10 + i] = (byte) 2; } } //将对应信息添加到图片前面 byte[] sendMsg = new byte[length + headInfoLength]; for (int i = 0; i < sendMsg.length; i++) { if (i < headInfoLength) { sendMsg[i] = headerInfo[i]; } else { sendMsg[i] = data[i - headInfoLength]; } } mChatService.write(sendMsg); } //蓝牙socket发送数据 public void write(byte[] out) { ConnectedThread r; synchronized (this) { if (mState != BluetoothState.STATE_CONNECTED) return; r = mConnectedThread; } r.write(out); } public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { } } 蓝牙接收数据:接收到的数据都是字节数据,我们需要把数据进行整合成对应的图片或视频信息,因为发送时分包机制,所以整合的时候要确保整张图片发送完毕才开始整合,具体流程是先获取前六位标志位,然后获取第7到10位的图片大小,再获取第11位到14位的动作信息,具体代码如下: public void run() { byte[] buffer; ArrayList arr_byte = new ArrayList(); while (true) { try { boolean valid = true; //判断前六位是不是012345 for (int i = 0; i < 6; i++) { int t = mmInStream.read(); if (t != i) { valid = false; //前六位判断完了跳出循环 break; } } if (valid) { //获取图片大小 byte[] bufLength = new byte[4]; for (int i = 0; i < 4; i++) { bufLength[i] = ((Integer) mmInStream.read()).byteValue(); } int TextCount = 0; int PhotoCount = 0; int VideoCount = 0; //获取动作信息 for (int i = 0; i < 4; i++) { int read = mmInStream.read(); if (read == 0) { TextCount++; } else if (read == 1) { PhotoCount++; } else if (read == 2) { VideoCount++; } } //获取图片的字节 int length = ByteArrayToInt(bufLength); buffer = new byte[length]; for (int i = 0; i < length; i++) { buffer[i] = ((Integer) mmInStream.read()).byteValue(); } //通过handler发出去 Message msg = Message.obtain(); msg.what = BluetoothState.MESSAGE_READ; msg.obj = buffer; if (TextCount == 4) { msg.arg1 = 0; mHandler.sendMessage(msg); } else if (PhotoCount == 4) { msg.arg1 = 1; mHandler.sendMessage(msg); } else if (VideoCount == 4) { msg.arg1 = 2; mHandler.sendMessage(msg); } } } catch (IOException e) { connectionLost(); BluetoothService.this.start(BluetoothService.this.isAndroid); break; } catch (Exception e) { e.printStackTrace(); } }} 下面分别是发送端和接受端的完整代码: 发送端SendClient代码部分: layout文件: 发射端的主界面: public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private static final String TAG = MainActivity.class.getName(); private static final int REQUEST_BLUETOOTH_ENABLE = 100; private BluetoothUtil mBt; private Camera mCamera; private SurfaceHolder mSurfaceHolder; private int mWidth; private int mHeight; private EditText mInput; private boolean isBluetoothConnnect; public Camera.Size size; private boolean mark = true; private int count; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBt = new BluetoothUtil(this); mInput = (EditText) findViewById(R.id.input); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView); mSurfaceHolder = surfaceView.getHolder(); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mSurfaceHolder.addCallback(this); initBlue(); } private void initBlue() { /** * reveice data */ mBt.setOnDataReceivedListener(new BluetoothUtil.OnDataReceivedListener() { public void onDataReceived(byte[] data, String message) { } }); mBt.setBluetoothConnectionListener(new BluetoothUtil.BluetoothConnectionListener() { public void onDeviceConnected(String name, String address) { isBluetoothConnnect = true; Toast.makeText(getApplicationContext(), "连接到 " + name + "\n" + address, Toast.LENGTH_SHORT).show(); } public void onDeviceDisconnected() { isBluetoothConnnect = false; //断开蓝牙连接 Toast.makeText(getApplicationContext(), "蓝牙断开", Toast.LENGTH_SHORT).show(); } public void onDeviceConnectionFailed() { Toast.makeText(getApplicationContext(), "无法连接", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) { if (resultCode == Activity.RESULT_OK) mBt.connect(data); } else if (requestCode == BluetoothState.REQUEST_ENABLE_BT) { if (resultCode == Activity.RESULT_OK) { mBt.setupService(); mBt.startService(BluetoothState.DEVICE_ANDROID); } else { finish(); } } } public void onStart() { super.onStart(); if (!mBt.isBluetoothEnabled()) { //打开蓝牙 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT); } else { if (!mBt.isServiceAvailable()) { //开启监听 mBt.setupService(); mBt.startService(BluetoothState.DEVICE_ANDROID); } } } @Override protected void onDestroy() { super.onDestroy(); mBt.stopService(); releaseCamera(); } private void releaseCamera() { if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.setPreviewCallbackWithBuffer(null); mCamera.stopPreview();// 停掉原来摄像头的预览 mCamera.release(); mCamera = null; } } @Override public void surfaceCreated(SurfaceHolder holder) { try { mCamera = Camera.open(); Camera.Parameters mPara = mCamera.getParameters(); List pictureSizes = mCamera.getParameters().getSupportedPictureSizes(); List previewSizes = mCamera.getParameters().getSupportedPreviewSizes(); int previewSizeIndex = -1; Camera.Size psize; int height_sm = 999999; int width_sm = 999999; //获取设备最小分辨率图片,图片越清晰,传输越卡 for (int i = 0; i < previewSizes.size(); i++) { psize = previewSizes.get(i); if (psize.height 发射端主界面 public class MainActivity extends AppCompatActivity { private BluetoothUtil mBt; private ImageView mPhoto; private ImageView mVideo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBt = new BluetoothUtil(this); initBlue(); initView(); } private void initView() { mPhoto = (ImageView) findViewById(R.id.photo); mVideo = (ImageView) findViewById(R.id.video); } private void initBlue() { if (!mBt.isBluetoothAvailable()) { Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show(); finish(); } mBt.setOnDataReceivedListener(new BluetoothUtil.OnDataReceivedListener() { public void onDataReceived(byte[] data, String message) { if (message.equals("text") && data.length != 0) { String text = new String(data); Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show(); } else if (message.equals("photo") && data.length != 0) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); mPhoto.setImageBitmap(bitmap); } else if (message.equals("video") && data.length != 0) { mVideo.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)); } } }); mBt.setBluetoothConnectionListener(new BluetoothUtil.BluetoothConnectionListener() { public void onDeviceConnected(String name, String address) { Toast.makeText(MainActivity.this,"蓝牙已连接",Toast.LENGTH_SHORT).show(); } public void onDeviceDisconnected() { Toast.makeText(MainActivity.this,"蓝牙已断开",Toast.LENGTH_SHORT).show(); } public void onDeviceConnectionFailed() { } }); } public void Click(View view) { if (mBt.getServiceState() == BluetoothState.STATE_CONNECTED) { mBt.disconnect(); } else { Intent intent = new Intent(getApplicationContext(), BluetoothActivity.class); startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) { if (resultCode == Activity.RESULT_OK) mBt.connect(data); } else if (requestCode == BluetoothState.REQUEST_ENABLE_BT) { if (resultCode == Activity.RESULT_OK) { mBt.setupService(); mBt.startService(BluetoothState.DEVICE_ANDROID); } else { finish(); } } } public void onStart() { super.onStart(); if (!mBt.isBluetoothEnabled()) { //打开蓝牙 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT); } else { if (!mBt.isServiceAvailable()) { //开启监听 mBt.setupService(); mBt.startService(BluetoothState.DEVICE_ANDROID); } } } } #蓝牙列表界面好状态码的类和发射端的一样,就不帖了,下面是接收端的BluetoothUtil public class BluetoothUtil { private BluetoothStateListener mBluetoothStateListener = null; private OnDataReceivedListener mDataReceivedListener = null; private BluetoothConnectionListener mBluetoothConnectionListener = null; private AutoConnectionListener mAutoConnectionListener = null; private Context mContext; private BluetoothAdapter mBluetoothAdapter = null; private BluetoothService mChatService = null; private String mDeviceName = null; private String mDeviceAddress = null; private boolean isAutoConnecting = false; private boolean isAutoConnectionEnabled = false; private boolean isConnected = false; private boolean isConnecting = false; private boolean isServiceRunning = false; private String keyword = ""; private boolean isAndroid = BluetoothState.DEVICE_ANDROID; private BluetoothConnectionListener bcl; private int c = 0; private static int headInfoLength = 10; //获取蓝牙adapter public BluetoothUtil(Context context) { mContext = context; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } //判断蓝牙是否可用 public boolean isBluetoothEnable() { return mBluetoothAdapter.isEnabled(); } public interface BluetoothStateListener { public void onServiceStateChanged(int state); } public interface OnDataReceivedListener { public void onDataReceived(byte[] data, String message); } public interface BluetoothConnectionListener { public void onDeviceConnected(String name, String address); public void onDeviceDisconnected(); public void onDeviceConnectionFailed(); } public interface AutoConnectionListener { public void onAutoConnectionStarted(); public void onNewConnection(String name, String address); } public boolean isBluetoothAvailable() { try { if (mBluetoothAdapter == null || mBluetoothAdapter.getAddress().equals(null)) return false; } catch (NullPointerException e) { return false; } return true; } public boolean isBluetoothEnabled() { return mBluetoothAdapter.isEnabled(); } public boolean isServiceAvailable() { return mChatService != null; } public boolean isAutoConnecting() { return isAutoConnecting; } public boolean startDiscovery() { return mBluetoothAdapter.startDiscovery(); } public boolean isDiscovery() { return mBluetoothAdapter.isDiscovering(); } public boolean cancelDiscovery() { return mBluetoothAdapter.cancelDiscovery(); } public void setupService() { mChatService = new BluetoothService(mContext, mHandler); } public BluetoothAdapter getBluetoothAdapter() { return mBluetoothAdapter; } public int getServiceState() { if(mChatService != null) return mChatService.getState(); else return -1; } //开启蓝牙一直监听是否连接的状态 public void startService(boolean isAndroid) { if (mChatService != null) { if (mChatService.getState() == BluetoothState.STATE_NONE) { isServiceRunning = true; mChatService.start(isAndroid); BluetoothUtil.this.isAndroid = isAndroid; } } } public void stopService() { if (mChatService != null) { isServiceRunning = false; mChatService.stop(); } new Handler().postDelayed(new Runnable() { public void run() { if (mChatService != null) { isServiceRunning = false; mChatService.stop(); } } }, 500); } public void setDeviceTarget(boolean isAndroid) { stopService(); startService(isAndroid); BluetoothUtil.this.isAndroid = isAndroid; } @SuppressLint("HandlerLeak") private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case BluetoothState.MESSAGE_WRITE: break; case BluetoothState.MESSAGE_READ: String str = null; int arg1 = msg.arg1; if(arg1==0){ str="text"; }else if(arg1==1){ str="photo"; }else if(arg1==2){ str="video"; } byte[] readBuf = (byte[]) msg.obj; // String readMessage = new String(readBuf); if(readBuf != null && readBuf.length > 0) { if(mDataReceivedListener != null) mDataReceivedListener.onDataReceived(readBuf, str); } break; case BluetoothState.MESSAGE_DEVICE_NAME: mDeviceName = msg.getData().getString(BluetoothState.DEVICE_NAME); mDeviceAddress = msg.getData().getString(BluetoothState.DEVICE_ADDRESS); if(mBluetoothConnectionListener != null) mBluetoothConnectionListener.onDeviceConnected(mDeviceName, mDeviceAddress); isConnected = true; break; case BluetoothState.MESSAGE_TOAST: Toast.makeText(mContext, msg.getData().getString(BluetoothState.TOAST) , Toast.LENGTH_SHORT).show(); break; case BluetoothState.MESSAGE_STATE_CHANGE: if(mBluetoothStateListener != null) mBluetoothStateListener.onServiceStateChanged(msg.arg1); if(isConnected && msg.arg1 != BluetoothState.STATE_CONNECTED) { if(mBluetoothConnectionListener != null) mBluetoothConnectionListener.onDeviceDisconnected(); if(isAutoConnectionEnabled) { isAutoConnectionEnabled = false; autoConnect(keyword); } isConnected = false; mDeviceName = null; mDeviceAddress = null; } if(!isConnecting && msg.arg1 == BluetoothState.STATE_CONNECTING) { isConnecting = true; } else if(isConnecting) { if(msg.arg1 != BluetoothState.STATE_CONNECTED) { if(mBluetoothConnectionListener != null) mBluetoothConnectionListener.onDeviceConnectionFailed(); } isConnecting = false; } break; } } }; public static int ByteArrayToInt(byte b[]) throws Exception { ByteArrayInputStream buf = new ByteArrayInputStream(b); DataInputStream dis= new DataInputStream(buf); return dis.readInt(); } public static byte[] intToByteArray(int i) throws Exception { ByteArrayOutputStream buf = new ByteArrayOutputStream(); DataOutputStream dos= new DataOutputStream(buf); dos.writeInt(i); byte[] b = buf.toByteArray(); dos.close(); buf.close(); return b; } public void stopAutoConnect() { isAutoConnectionEnabled = false; } public BluetoothDevice connect(Intent data) { String address = data.getExtras().getString(BluetoothState.EXTRA_DEVICE_ADDRESS); BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); mChatService.connect(device); return device; } public void connect(String address) { BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); mChatService.connect(device); } public void disconnect() { if(mChatService != null) { isServiceRunning = false; mChatService.stop(); if(mChatService.getState() == BluetoothState.STATE_NONE) { isServiceRunning = true; mChatService.start(BluetoothUtil.this.isAndroid); } } } public void setBluetoothStateListener (BluetoothStateListener listener) { mBluetoothStateListener = listener; } public void setOnDataReceivedListener (OnDataReceivedListener listener) { mDataReceivedListener = listener; } public void setBluetoothConnectionListener (BluetoothConnectionListener listener) { mBluetoothConnectionListener = listener; } public void setAutoConnectionListener(AutoConnectionListener listener) { mAutoConnectionListener = listener; } public void enable() { mBluetoothAdapter.enable(); } public void send(byte[] data, boolean CRLF) { if(mChatService.getState() == BluetoothState.STATE_CONNECTED) { if(CRLF) { byte[] data2 = new byte[data.length + 2]; for(int i = 0 ; i < data.length ; i++) data2[i] = data[i]; data2[data2.length - 2] = 0x0A; data2[data2.length - 1] = 0x0D; mChatService.write(data2); } else { mChatService.write(data); } } } public void send(String data, boolean CRLF) { if(mChatService.getState() == BluetoothState.STATE_CONNECTED) { if(CRLF) data += "\r\n"; mChatService.write(data.getBytes()); } } public void send(byte[] data){ int length = data.length; byte[] length_b = null; try { length_b= intToByteArray(length); } catch (Exception e) { e.printStackTrace(); } if(length_b == null)return; byte[] headerInfo = new byte[headInfoLength]; for (int i = 0; i < headInfoLength - 4; i++) { headerInfo[i] = (byte) i; } for (int i = 0; i < 4; i++) { headerInfo[6+i] = length_b[i]; } byte[] sendMsg = new byte[length + headInfoLength]; for (int i = 0; i < sendMsg.length; i++) { if(i < headInfoLength){ sendMsg[i] = headerInfo[i]; }else{ sendMsg[i] = data[i - headInfoLength]; } } mChatService.write(sendMsg); } public String getConnectedDeviceName() { return mDeviceName; } public String getConnectedDeviceAddress() { return mDeviceAddress; } public String[] getPairedDeviceName() { int c = 0; Set devices = mBluetoothAdapter.getBondedDevices(); String[] name_list = new String[devices.size()]; for(BluetoothDevice device : devices) { name_list[c] = device.getName(); c++; } return name_list; } public String[] getPairedDeviceAddress() { int c = 0; Set devices = mBluetoothAdapter.getBondedDevices(); String[] address_list = new String[devices.size()]; for(BluetoothDevice device : devices) { address_list[c] = device.getAddress(); c++; } return address_list; } public void autoConnect(String keywordName) { if(!isAutoConnectionEnabled) { keyword = keywordName; isAutoConnectionEnabled = true; isAutoConnecting = true; if(mAutoConnectionListener != null) mAutoConnectionListener.onAutoConnectionStarted(); final ArrayList arr_filter_address = new ArrayList(); final ArrayList arr_filter_name = new ArrayList(); String[] arr_name = getPairedDeviceName(); String[] arr_address = getPairedDeviceAddress(); for(int i = 0 ; i < arr_name.length ; i++) { if(arr_name[i].contains(keywordName)) { arr_filter_address.add(arr_address[i]); arr_filter_name.add(arr_name[i]); } } bcl = new BluetoothConnectionListener() { public void onDeviceConnected(String name, String address) { bcl = null; isAutoConnecting = false; } public void onDeviceDisconnected() { } public void onDeviceConnectionFailed() { Log.e("CHeck", "Failed"); if(isServiceRunning) { if(isAutoConnectionEnabled) { c++; if(c >= arr_filter_address.size()) c = 0; connect(arr_filter_address.get(c)); Log.e("CHeck", "Connect"); if(mAutoConnectionListener != null) mAutoConnectionListener.onNewConnection(arr_filter_name.get(c) , arr_filter_address.get(c)); } else { bcl = null; isAutoConnecting = false; } } } }; setBluetoothConnectionListener(bcl); c = 0; if(mAutoConnectionListener != null) mAutoConnectionListener.onNewConnection(arr_name[c], arr_address[c]); if(arr_filter_address.size() > 0) connect(arr_filter_address.get(c)); else Toast.makeText(mContext, "Device name mismatch", Toast.LENGTH_SHORT).show(); } } } 接收端的BluetoothService,核心部分是ConnectedThread这个线程 public class BluetoothService { private static final String TAG = "Bluetooth Service"; private static final String NAME_SECURE = "Bluetooth Secure"; private static final UUID UUID_ANDROID_DEVICE = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); private static final UUID UUID_OTHER_DEVICE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private final BluetoothAdapter mAdapter; private final Handler mHandler; private AcceptThread mSecureAcceptThread; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; private int mState; private boolean isAndroid = BluetoothState.DEVICE_ANDROID; public BluetoothService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = BluetoothState.STATE_NONE; mHandler = handler; } private synchronized void setState(int state) { Log.d(TAG, "setState() " + mState + " -> " + state); mState = state; mHandler.obtainMessage(BluetoothState.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } public synchronized int getState() { return mState; } //开启子线程 public synchronized void start(boolean isAndroid) { // Cancel any thread attempting to make a connection if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(BluetoothState.STATE_LISTEN); //开启子线程 if (mSecureAcceptThread == null) { mSecureAcceptThread = new AcceptThread(isAndroid); mSecureAcceptThread.start(); BluetoothService.this.isAndroid = isAndroid; } } public synchronized void connect(BluetoothDevice device) { // Cancel any thread attempting to make a connection if (mState == BluetoothState.STATE_CONNECTING) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } } // Cancel any thread currently running a connection if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // Start the thread to connect with the given device mConnectThread = new ConnectThread(device); mConnectThread.start(); setState(BluetoothState.STATE_CONNECTING); } /** * Start the ConnectedThread to begin managing a Bluetooth connection * * @param socket The BluetoothSocket on which the connection was made * @param device The BluetoothDevice that has been connected */ public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread = null; } mConnectedThread = new ConnectedThread(socket, socketType); mConnectedThread.start(); Message msg = mHandler.obtainMessage(BluetoothState.MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(BluetoothState.DEVICE_NAME, device.getName()); bundle.putString(BluetoothState.DEVICE_ADDRESS, device.getAddress()); msg.setData(bundle); mHandler.sendMessage(msg); setState(BluetoothState.STATE_CONNECTED); } public synchronized void stop() { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread.kill(); mSecureAcceptThread = null; } setState(BluetoothState.STATE_NONE); } public void write(byte[] out) { ConnectedThread r; synchronized (this) { if (mState != BluetoothState.STATE_CONNECTED) return; r = mConnectedThread; } r.write(out); } private void connectionFailed() { BluetoothService.this.start(BluetoothService.this.isAndroid); } private void connectionLost() { BluetoothService.this.start(BluetoothService.this.isAndroid); } //监听蓝牙连接的线程 private class AcceptThread extends Thread { private BluetoothServerSocket mmServerSocket; private String mSocketType; boolean isRunning = true; public AcceptThread(boolean isAndroid) { BluetoothServerSocket tmp = null; try { if (isAndroid) //获取蓝牙socket tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_ANDROID_DEVICE); else tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_OTHER_DEVICE); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { setName("AcceptThread" + mSocketType); BluetoothSocket socket = null; //死循环监听蓝牙连接状态,首次今进入一定满足条件,蓝牙连上后,循环停止 while (mState != BluetoothState.STATE_CONNECTED && isRunning) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } if (socket != null) { synchronized (BluetoothService.this) { switch (mState) { case BluetoothState.STATE_LISTEN: case BluetoothState.STATE_CONNECTING: connected(socket, socket.getRemoteDevice(), mSocketType); break; case BluetoothState.STATE_NONE: case BluetoothState.STATE_CONNECTED: try { socket.close(); } catch (IOException e) { } break; } } } } } public void cancel() { try { mmServerSocket.close(); mmServerSocket = null; } catch (IOException e) { } } public void kill() { isRunning = false; } } private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; try { if (BluetoothService.this.isAndroid) tmp = device.createRfcommSocketToServiceRecord(UUID_ANDROID_DEVICE); else tmp = device.createRfcommSocketToServiceRecord(UUID_OTHER_DEVICE); } catch (IOException e) { } mmSocket = tmp; } public void run() { mAdapter.cancelDiscovery(); try { mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { } connectionFailed(); return; } synchronized (BluetoothService.this) { mConnectThread = null; } connected(mmSocket, mmDevice, mSocketType); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } } public static int ByteArrayToInt(byte b[]) throws Exception { ByteArrayInputStream buf = new ByteArrayInputStream(b); DataInputStream dis = new DataInputStream(buf); return dis.readInt(); } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream;`` private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer; ArrayList arr_byte = new ArrayList(); while (true) { try { boolean valid = true; //判断前六位是不是12345 for (int i = 0; i < 6; i++) { int t = mmInStream.read(); if (t != i) { valid = false; break; } } if (valid) { byte[] bufLength = new byte[4]; for (int i = 0; i < 4; i++) { bufLength[i] = ((Integer) mmInStream.read()).byteValue(); } int textCount = 0; int photoCount = 0; int videoCount = 0; for (int i = 0; i < 4; i++) { int read = mmInStream.read(); if (read == 0) { textCount++; } else if (read == 1) { photoCount++; } else if (read == 2) { videoCount++; } } int length = ByteArrayToInt(bufLength); buffer = new byte[length]; for (int i = 0; i < length; i++) { buffer[i] = ((Integer) mmInStream.read()).byteValue(); } Message msg = Message.obtain(); msg.what = BluetoothState.MESSAGE_READ; msg.obj = buffer; if (textCount == 4) { msg.arg1 = 0; mHandler.sendMessage(msg); } else if (photoCount == 4) { msg.arg1 = 1; mHandler.sendMessage(msg); } else if (videoCount == 4) { msg.arg1 = 2; mHandler.sendMessage(msg); } } } catch (IOException e) { connectionLost(); BluetoothService.this.start(BluetoothService.this.isAndroid); break; } catch (Exception e) { e.printStackTrace(); } } } public void write(byte[] buffer) { try {/* byte[] buffer2 = new byte[buffer.length + 2]; for(int i = 0 ; i < buffer.length ; i++) buffer2[i] = buffer[i]; buffer2[buffer2.length - 2] = 0x0A; buffer2[buffer2.length - 1] = 0x0D;*/ mmOutStream.write(buffer); } catch (IOException e) { } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }} 权限:
|
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |