兩臺手機設備之間能夠正常進行藍牙配對(藍牙模塊兒和硬件掛鉤,所以需要兩臺真機)
socket實現藍牙文本傳輸
實現圖片傳輸
實現實時視頻傳輸
代碼下載:https://download.csdn.net/download/m0_37781149/10434336
Bluetooth的MTU(最大傳輸單元)是20字節,即一次最多能發送20個字節,若超過20個字節,建議採用分包傳輸的方式。在傳輸圖片和視頻的時候處理方式是將圖片轉換成字節byte,並在圖片前面添加一個頭,加入相應的標誌位,例如圖片大小。然後在接受端進行整合,獲取圖片大小(字節長度),進行相應判斷,整合成圖片再顯示。下面分模塊兒講解:
藍牙掃描
通過註冊廣播來獲取藍牙列表,藍牙連接狀態發生改變時候系統都會發送相應廣播,獲取相應的藍牙列表並添加到list中,顯示出來
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//當發現藍牙設備
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
String strNoFound = getIntent().getStringExtra("no_devices_found");
if (strNoFound == null)
strNoFound = "No devices found";
if (mPairedDevicesArrayAdapter.getItem(0).equals(strNoFound)) {
mPairedDevicesArrayAdapter.remove(strNoFound);
}
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
String strSelectDevice = getIntent().getStringExtra("select_device");
if (strSelectDevice == null)
strSelectDevice = "Select a device to connect";
setTitle(strSelectDevice);
}
}
};
//掃描藍牙設備
private void doDiscovery() {
mPairedDevicesArrayAdapter.clear();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String strNoFound = getIntent().getStringExtra("no_devices_found");
if (strNoFound == null)
strNoFound = "No devices found";
mPairedDevicesArrayAdapter.add(strNoFound);
}
String strScanning = getIntent().getStringExtra("scanning");
if (strScanning == null)
strScanning = "Scanning for devices...";
setProgressBarIndeterminateVisibility(true);
setTitle(strScanning);
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
mBtAdapter.startDiscovery();
}
點擊對應的條目可以回退到MainActivity,並將對應的mac地址攜帶回來,用於藍牙配對連接
//攜帶藍牙地址返回主界面
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
if (mBtAdapter.isDiscovering())
mBtAdapter.cancelDiscovery();
String strNoFound = getIntent().getStringExtra("no_devices_found");
if (strNoFound == null)
strNoFound = "No devices found";
if (!((TextView) v).getText().toString().equals(strNoFound)) {
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent intent = new Intent();
intent.putExtra(BluetoothState.EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();
}
}
};
藍牙連接核心工具類BluetoothUtil,藍牙狀態BluetoothState和BluetoothService
藍牙配對基本過程:在APP啓動的時候,開啓一個線程一直監聽藍牙的連接狀態,這個子線程是啓動時是死循環狀態,在藍牙連接成功時會停止,在藍牙意外斷開時候會重新處於監聽狀態
public void onStart() {
super.onStart();
if (!mBt.isBluetoothEnabled()) {
//打開藍牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
} else {
if (!mBt.isServiceAvailable()) {
//開啓監聽
mBt.setupService();
mBt.startService(BluetoothState.DEVICE_ANDROID);
}
}
}
public void setupService() {
mChatService = new BluetoothService(mContext, mHandler);
}
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = BluetoothState.STATE_NONE;
mHandler = handler;
}
//開啓藍牙一直監聽是否連接的狀態
public void startService(boolean isAndroid) {
if (mChatService != null) {
if (mChatService.getState() == BluetoothState.STATE_NONE) {
isServiceRunning = true;
mChatService.start(isAndroid);
BluetoothUtil.this.isAndroid = isAndroid;
}
}
}
//開啓子線程
public synchronized void start(boolean isAndroid) {
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(BluetoothState.STATE_LISTEN);
//開啓子線程
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(isAndroid);
mSecureAcceptThread.start();
BluetoothService.this.isAndroid = isAndroid;
}
}
//監聽藍牙連接的線程
private class AcceptThread extends Thread {
private BluetoothServerSocket mmServerSocket;
private String mSocketType;
boolean isRunning = true;
public AcceptThread(boolean isAndroid) {
BluetoothServerSocket tmp = null;
try {
if (isAndroid)
//獲取藍牙socket
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_ANDROID_DEVICE);
else
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_OTHER_DEVICE);
} catch (IOException e) {
}
mmServerSocket = tmp;
}
public void run() {
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
//死循環監聽藍牙連接狀態,首次進入一定滿足條件,藍牙連上後,循環停止
while (mState != BluetoothState.STATE_CONNECTED && isRunning) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case BluetoothState.STATE_LISTEN:
case BluetoothState.STATE_CONNECTING:
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case BluetoothState.STATE_NONE:
case BluetoothState.STATE_CONNECTED:
try {
socket.close();
} catch (IOException e) {
}
break;
}
}
}
}
}
public void cancel() {
try {
mmServerSocket.close();
mmServerSocket = null;
} catch (IOException e) {
}
}
public void kill() {
isRunning = false;
}
}
核心部分:藍牙發送和接受數據,藍牙發送數據處理過程,比如發送一張圖片,肯定是大於20字節的,藍牙是採用分包發送機制,在處理的時候,我們把圖片轉換成字節,並在圖片前面添加一個頭,這個頭是固定字節的長度,不能太小,因爲拍攝圖片的時候,圖片有大有小,避免和圖面裝換成字節後產生衝突。這個頭裏面主要攜帶兩個信息,當然也可以是多個,自由定義。兩個信息分別是,圖片的大小,即字節長度length,還有一個是動作,例如傳照片,傳文本,實時視頻傳輸,代碼如下:
//添加頭髮送數據
public void send(byte[] data, String str) {
int length = data.length;
byte[] length_b = null;
try {
length_b = intToByteArray(length);
} catch (Exception e) {
e.printStackTrace();
}
if (length_b == null) return;
//獲得一個字節長度爲14的byte數組 headInfoLength爲14
byte[] headerInfo = new byte[headInfoLength];
//前六位添加012345的標誌位
for (int i = 0; i < headInfoLength - 8; i++) {
headerInfo[i] = (byte) i;
}
//7到10位添加圖片大小的字節長度
for (int i = 0; i < 4; i++) {
headerInfo[6 + i] = length_b[i];
}
//11到14位添加動作信息
if (str.equals("text")) {
for (int i = 0; i < 4; i++) {
headerInfo[10 + i] = (byte) 0;
}
} else if (str.equals("photo")) {
for (int i = 0; i < 4; i++) {
headerInfo[10 + i] = (byte) 1;
}
} else if (str.equals("video")) {
for (int i = 0; i < 4; i++) {
headerInfo[10 + i] = (byte) 2;
}
}
//將對應信息添加到圖片前面
byte[] sendMsg = new byte[length + headInfoLength];
for (int i = 0; i < sendMsg.length; i++) {
if (i < headInfoLength) {
sendMsg[i] = headerInfo[i];
} else {
sendMsg[i] = data[i - headInfoLength];
}
}
mChatService.write(sendMsg);
}
//藍牙socket發送數據
public void write(byte[] out) {
ConnectedThread r;
synchronized (this) {
if (mState != BluetoothState.STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(out);
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
}
}
藍牙接收數據:接收到的數據都是字節數據,我們需要把數據進行整合成對應的圖片或視頻信息,因爲發送時分包機制,所以整合的時候要確保整張圖片發送完畢纔開始整合,具體流程是先獲取前六位標誌位,然後獲取第7到10位的圖片大小,再獲取第11位到14位的動作信息,具體代碼如下:
public void run() {
byte[] buffer;
ArrayList<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"/>