目标
两台手机设备之间能够正常进行蓝牙配对(蓝牙模块儿和硬件挂钩,所以需要两台真机)
socket实现蓝牙文本传输
实现图片传输
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<Integer> arr_byte = new ArrayList<Integer>();
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文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rejointech.sendclient.MainActivity">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="300dp"/>
<EditText
android:layout_marginTop="20dp"
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入要发送的文本信息"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="bluetooth"
android:text="蓝牙"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="文本"
android:onClick="sendText"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:onClick="sendPhoto"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="图片"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="视频"
android:onClick="sendVideo"
android:textColor="#000"
android:textSize="18sp"/>
</LinearLayout>
</LinearLayout>
发射端的主界面:
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<Camera.Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
List<Camera.Size> 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 <= height_sm && psize.width <= width_sm) {
previewSizeIndex = i;
height_sm = psize.height;
width_sm = psize.width;
}
}
if (previewSizeIndex != -1) {
mWidth = previewSizes.get(previewSizeIndex).width;
mHeight = previewSizes.get(previewSizeIndex).height;
mPara.setPreviewSize(mWidth, mHeight);
}
mCamera.setParameters(mPara);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
size = mCamera.getParameters().getPreviewSize();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
//蓝牙搜索配对
public void bluetooth(View view) {
if (mBt.getServiceState() == BluetoothState.STATE_CONNECTED) {
mBt.disconnect();
} else {
Intent intent = new Intent(getApplicationContext(), BluetoothActivity.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
}
//发送文本信息
public void sendText(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
String input = mInput.getText().toString().trim();
if (input != null && !input.isEmpty()) {
mBt.send(input.getBytes(), "TEXT");
} else {
Toast.makeText(MainActivity.this, "输入信息不能为空", Toast.LENGTH_SHORT).show();
}
}
//发送图片
public void sendPhoto(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
mark = false;//关闭视频发送
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
mBt.send(bytes, "photo");
mCamera.startPreview();
}
});
}
//发送视频 其实也是发送一张一张的图片
public void sendVideo(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
mark = true;
new Thread(new Runnable() {
@Override
public void run() {
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
count++;
Camera.Size size = camera.getParameters().getPreviewSize();
final YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, mWidth, mHeight), 100, stream);
byte[] imageBytes = stream.toByteArray();
if (count % 2 == 0 && mark) {
mBt.send(imageBytes, "video");
}
}
});
}
}).start();
}
}
蓝牙列表的页面
public class BluetoothActivity extends AppCompatActivity {
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private Set<BluetoothDevice> pairedDevices;
private Button scanButton;
private SharedPreferences mSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int listId = getIntent().getIntExtra("layout_list", R.layout.device_list);
setContentView(listId);
String strBluetoothDevices = getIntent().getStringExtra("bluetooth_devices");
if (strBluetoothDevices == null)
strBluetoothDevices = "Bluetooth Devices";
setTitle(strBluetoothDevices);
setResult(Activity.RESULT_CANCELED);
scanButton = (Button) findViewById(R.id.button_scan);
String strScanDevice = getIntent().getStringExtra("scan_for_devices");
if (strScanDevice == null)
strScanDevice = "SCAN FOR DEVICES";
scanButton.setText("搜索");
scanButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
doDiscovery();
}
});
int layout_text = getIntent().getIntExtra("layout_text", R.layout.device_name);
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, layout_text);
ListView pairedListView = (ListView) findViewById(R.id.list_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = "No devices found";
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onStart() {
super.onStart();
}
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 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();
}
}
};
//扫描蓝牙设备
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();
}
protected void onDestroy() {
super.onDestroy();
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
this.unregisterReceiver(mReceiver);
this.finish();
}
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<BluetoothDevice> 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<BluetoothDevice> 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<String> arr_filter_address = new ArrayList<String>();
final ArrayList<String> arr_filter_name = new ArrayList<String>();
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();
}
}
BluetoothState蓝牙状态码
public class BluetoothState {
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_NULL = -1;
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;
public static final int REQUEST_CONNECT_DEVICE = 384;
public static final int REQUEST_ENABLE_BT = 385;
public static final String DEVICE_NAME = "device_name";
public static final String DEVICE_ADDRESS = "device_address";
public static final String TOAST = "toast";
public static final boolean DEVICE_ANDROID = true;
public static final boolean DEVICE_OTHER = false;
public static String EXTRA_DEVICE_ADDRESS = "device_address";
}
BluetoothService蓝牙状态监听和配对连接
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) {
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) {
if (mState == BluetoothState.STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(BluetoothState.STATE_CONNECTING);
}
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)
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<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
boolean valid = true;
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 length = ByteArrayToInt(bufLength);
buffer = new byte[length];
for (int i = 0; i < length; i++) {
buffer[i] = ((Integer) mmInStream.read()).byteValue();
}
mHandler.obtainMessage(BluetoothState.MESSAGE_READ,
buffer).sendToTarget();
}
} catch (IOException e) {
connectionLost();
BluetoothService.this.start(BluetoothService.this.isAndroid);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
}
以上是发射端部分ReceiveClient,下面是蓝牙接受端部分:
发射端layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rejointech.receiveclient.MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/photo"/>
<ImageView
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/video"/>
<Button
android:text="蓝牙"
android:textColor="#000"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="Click"/>
</LinearLayout>
发射端主界面
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<BluetoothDevice> 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<BluetoothDevice> 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<String> arr_filter_address = new ArrayList<String>();
final ArrayList<String> arr_filter_name = new ArrayList<String>();
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<Integer> arr_byte = new ArrayList<Integer>();
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) {
}
}
}
两台手机设备之间能够正常进行蓝牙配对(蓝牙模块儿和硬件挂钩,所以需要两台真机)
socket实现蓝牙文本传输
实现图片传输
实现实时视频传输
代码下载:https://download.youkuaiyun.com/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<Integer> arr_byte = new ArrayList<Integer>();
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文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rejointech.sendclient.MainActivity">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="300dp"/>
<EditText
android:layout_marginTop="20dp"
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入要发送的文本信息"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="bluetooth"
android:text="蓝牙"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="文本"
android:onClick="sendText"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:onClick="sendPhoto"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="图片"
android:textColor="#000"
android:textSize="18sp"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="视频"
android:onClick="sendVideo"
android:textColor="#000"
android:textSize="18sp"/>
</LinearLayout>
</LinearLayout>
发射端的主界面:
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<Camera.Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
List<Camera.Size> 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 <= height_sm && psize.width <= width_sm) {
previewSizeIndex = i;
height_sm = psize.height;
width_sm = psize.width;
}
}
if (previewSizeIndex != -1) {
mWidth = previewSizes.get(previewSizeIndex).width;
mHeight = previewSizes.get(previewSizeIndex).height;
mPara.setPreviewSize(mWidth, mHeight);
}
mCamera.setParameters(mPara);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
size = mCamera.getParameters().getPreviewSize();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
//蓝牙搜索配对
public void bluetooth(View view) {
if (mBt.getServiceState() == BluetoothState.STATE_CONNECTED) {
mBt.disconnect();
} else {
Intent intent = new Intent(getApplicationContext(), BluetoothActivity.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
}
//发送文本信息
public void sendText(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
String input = mInput.getText().toString().trim();
if (input != null && !input.isEmpty()) {
mBt.send(input.getBytes(), "TEXT");
} else {
Toast.makeText(MainActivity.this, "输入信息不能为空", Toast.LENGTH_SHORT).show();
}
}
//发送图片
public void sendPhoto(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
mark = false;//关闭视频发送
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
mBt.send(bytes, "photo");
mCamera.startPreview();
}
});
}
//发送视频 其实也是发送一张一张的图片
public void sendVideo(View view) {
if (!isBluetoothConnnect) {
Toast.makeText(this, "请连接蓝牙", Toast.LENGTH_SHORT).show();
return;
}
mark = true;
new Thread(new Runnable() {
@Override
public void run() {
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
count++;
Camera.Size size = camera.getParameters().getPreviewSize();
final YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, mWidth, mHeight), 100, stream);
byte[] imageBytes = stream.toByteArray();
if (count % 2 == 0 && mark) {
mBt.send(imageBytes, "video");
}
}
});
}
}).start();
}
}
蓝牙列表的页面
public class BluetoothActivity extends AppCompatActivity {
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private Set<BluetoothDevice> pairedDevices;
private Button scanButton;
private SharedPreferences mSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int listId = getIntent().getIntExtra("layout_list", R.layout.device_list);
setContentView(listId);
String strBluetoothDevices = getIntent().getStringExtra("bluetooth_devices");
if (strBluetoothDevices == null)
strBluetoothDevices = "Bluetooth Devices";
setTitle(strBluetoothDevices);
setResult(Activity.RESULT_CANCELED);
scanButton = (Button) findViewById(R.id.button_scan);
String strScanDevice = getIntent().getStringExtra("scan_for_devices");
if (strScanDevice == null)
strScanDevice = "SCAN FOR DEVICES";
scanButton.setText("搜索");
scanButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
doDiscovery();
}
});
int layout_text = getIntent().getIntExtra("layout_text", R.layout.device_name);
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, layout_text);
ListView pairedListView = (ListView) findViewById(R.id.list_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = "No devices found";
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onStart() {
super.onStart();
}
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 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();
}
}
};
//扫描蓝牙设备
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();
}
protected void onDestroy() {
super.onDestroy();
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
this.unregisterReceiver(mReceiver);
this.finish();
}
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<BluetoothDevice> 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<BluetoothDevice> 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<String> arr_filter_address = new ArrayList<String>();
final ArrayList<String> arr_filter_name = new ArrayList<String>();
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();
}
}
BluetoothState蓝牙状态码
public class BluetoothState {
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_NULL = -1;
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;
public static final int REQUEST_CONNECT_DEVICE = 384;
public static final int REQUEST_ENABLE_BT = 385;
public static final String DEVICE_NAME = "device_name";
public static final String DEVICE_ADDRESS = "device_address";
public static final String TOAST = "toast";
public static final boolean DEVICE_ANDROID = true;
public static final boolean DEVICE_OTHER = false;
public static String EXTRA_DEVICE_ADDRESS = "device_address";
}
BluetoothService蓝牙状态监听和配对连接
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) {
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) {
if (mState == BluetoothState.STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(BluetoothState.STATE_CONNECTING);
}
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)
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<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
boolean valid = true;
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 length = ByteArrayToInt(bufLength);
buffer = new byte[length];
for (int i = 0; i < length; i++) {
buffer[i] = ((Integer) mmInStream.read()).byteValue();
}
mHandler.obtainMessage(BluetoothState.MESSAGE_READ,
buffer).sendToTarget();
}
} catch (IOException e) {
connectionLost();
BluetoothService.this.start(BluetoothService.this.isAndroid);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
}
以上是发射端部分ReceiveClient,下面是蓝牙接受端部分:
发射端layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rejointech.receiveclient.MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/photo"/>
<ImageView
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/video"/>
<Button
android:text="蓝牙"
android:textColor="#000"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="Click"/>
</LinearLayout>
发射端主界面
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<BluetoothDevice> 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<BluetoothDevice> 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<String> arr_filter_address = new ArrayList<String>();
final ArrayList<String> arr_filter_name = new ArrayList<String>();
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<Integer> arr_byte = new ArrayList<Integer>();
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) {
}
}
}
}
权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.CAMERA"/>