标签:
最近做了一个小项目,关于蓝牙的一个智能硬件。其中涉及到了蓝牙模块的操作。特记下蓝牙模块的操作过程。只记录下关于蓝牙部分的操作,具体业务逻辑不涉及其中。重点是记录下蓝牙的扫描、链接、通讯。
在使用蓝牙模块之前要判断设备是否支持蓝牙模块:
1 if (!getPackageManager().hasSystemFeature( 2 PackageManager.FEATURE_BLUETOOTH_LE)) { 3 Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT) 4 .show(); 5 }
定义Service,与蓝牙模块进行通讯,在后台运行:
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.njzoff.cushion.broadcast; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; import java.util.List; import java.util.UUID; /** * Service for managing connection and data communication with a GATT server hosted on a * given Bluetooth LE device. */ public class BluetoothLeService extends Service { private final static String TAG = BluetoothLeService.class.getSimpleName(); private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private BluetoothGatt mBluetoothGatt; public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; public final static String EXTRA_DATA = "com.example.bluetooth.le.EXTRA_DATA"; public final static UUID UUID_NOTIFY = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"); public final static UUID UUID_SERVICE = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"); public BluetoothGattCharacteristic mNotifyCharacteristic; public void WriteValue(String strValue) { mNotifyCharacteristic.setValue(strValue.getBytes()); mBluetoothGatt.writeCharacteristic(mNotifyCharacteristic); } public void findService(List<BluetoothGattService> gattServices) { Log.i(TAG, "Count is:" + gattServices.size()); for (BluetoothGattService gattService : gattServices) { Log.i(TAG, gattService.getUuid().toString()); Log.i(TAG, UUID_SERVICE.toString()); if(gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString())) { List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); Log.i(TAG, "Count is:" + gattCharacteristics.size()); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { if(gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString())) { Log.i(TAG, gattCharacteristic.getUuid().toString()); Log.i(TAG, UUID_NOTIFY.toString()); mNotifyCharacteristic = gattCharacteristic; setCharacteristicNotification(gattCharacteristic, true); broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); return; } } } } } // Implements callback methods for GATT events that the app cares about. For example, // connection change and services discovered. private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; Log.i(TAG, "oldStatus=" + status + " NewStates=" + newState); if(status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; mBluetoothGatt.close(); mBluetoothGatt = null; Log.i(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); } } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.w(TAG, "onServicesDiscovered received: " + status); findService(gatt.getServices()); } else { if(mBluetoothGatt.getDevice().getUuids() == null) Log.w(TAG, "onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.e(TAG, "OnCharacteristicWrite"); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.e(TAG, "OnCharacteristicWrite"); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor bd, int status) { Log.e(TAG, "onDescriptorRead"); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor bd, int status) { Log.e(TAG, "onDescriptorWrite"); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int a, int b) { Log.e(TAG, "onReadRemoteRssi"); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int a) { Log.e(TAG, "onReliableWriteCompleted"); } }; private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); sendBroadcast(intent); } private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); // This is special handling for the Heart Rate Measurement profile. Data parsing is // carried out as per profile specifications: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml // For all other profiles, writes the data formatted in HEX. final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { //final StringBuilder stringBuilder = new StringBuilder(data.length); //for(byte byteChar : data) // stringBuilder.append(String.format("%02X ", byteChar)); //intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); intent.putExtra(EXTRA_DATA, new String(data)); } sendBroadcast(intent); } public class LocalBinder extends Binder { public BluetoothLeService getService() { return BluetoothLeService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public boolean onUnbind(Intent intent) { // After using a given device, you should make sure that BluetoothGatt.close() is called // such that resources are cleaned up properly. In this particular example, close() is // invoked when the UI is disconnected from the Service. close(); return super.onUnbind(intent); } private final IBinder mBinder = new LocalBinder(); /** * Initializes a reference to the local Bluetooth adapter. * * @return Return true if the initialization is successful. */ public boolean initialize() { // For API level 18 and above, get a reference to BluetoothAdapter through // BluetoothManager. if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.e(TAG, "Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false; } return true; } /** * Connects to the GATT server hosted on the Bluetooth LE device. * * @param address The device address of the destination device. * * @return Return true if the connection is initiated successfully. The connection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } /* // Previously connected device. Try to reconnect. if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { mConnectionState = STATE_CONNECTING; return true; } else { return false; } } */ BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false. if(mBluetoothGatt != null) { mBluetoothGatt.close(); mBluetoothGatt = null; } mBluetoothGatt = device.connectGatt(this, false, mGattCallback); //mBluetoothGatt.connect(); Log.d(TAG, "Trying to create a new connection."); return true; } /** * Disconnects an existing connection or cancel a pending connection. The disconnection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.disconnect(); } /** * After using a given BLE device, the app must call this method to ensure resources are * released properly. */ public void close() { if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; } /** * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. * * @param characteristic The characteristic to read from. */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); } /** * Enables or disables notification on a give characteristic. * * @param characteristic Characteristic to act on. * @param enabled If true, enable notification. False otherwise. */ public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); /* // This is specific to Heart Rate Measurement. if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } */ } /** * Retrieves a list of supported GATT services on the connected device. This should be * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. * * @return A {@code List} of supported services. */ public List<BluetoothGattService> getSupportedGattServices() { if (mBluetoothGatt == null) return null; return mBluetoothGatt.getServices(); } }
定义BluetoothAdapter mBluetoothAdapter;
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter =bluetoothManager .getAdapter(); //取得系统蓝牙模块适配器
// 扫描设备 private void scanLeDevice(final boolean enable) { if (enable) { Log.d("SacanLeDevice", "1 step start ScanLedevice"); // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { if (mScanning) { mScanning = false; mBluetoothAdapter.stopLeScan( mLeScanCallback);//停止扫描 invalidateOptionsMenu(); } } }, SCAN_PERIOD); mScanning = true; // F000E0FF-0451-4000-B000-000000000000 liDevices.clear(); mHandler.sendEmptyMessage(0); mBluetoothAdapter.startLeScan(mLeScanCallback);//开始扫描设备 } else { Log.d("SacanLeDevice", "4 step stop Sacan device"); mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }
//蓝牙设备
private List<BluetoothDevice> liDevices = new ArrayList<BluetoothDevice>();
// 扫描蓝牙设备的回调
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi,
final byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d("SacanLeDevice", "2 step add device");
liDevices.add(device);
// mLeDeviceListAdapter.addDevice(device);
mHandler.sendEmptyMessage(1);
}
});
}
};
//通过handle取出扫描结果并进行其他操作,我这这里是判断扫描结果中是否有上次链接的缓存记录,如果有进行自动重连
// Hander
public final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1: // Notify change
Log.d("SacanLeDevice", "3 step cnnect device");
if (!CoushionApplication.isconnect && liDevices.size() > 0) {// 如果没有连接,并且已经扫描到蓝牙设备
SharedPreferences mySharedPreferences = getSharedPreferences(
"device", Activity.MODE_PRIVATE);
String address = mySharedPreferences.getString(
"DeviceAddress", "");// 获取上次链接的设备地址
if (!address.equals("")) {
for (int i = 0; i < liDevices.size(); i++) {
if (liDevices.get(i).getAddress().equals(address)) {
BluetoothLeService.connect(address);//根据地址链接蓝牙设备
break;
}
}
}
}
break;
}
}
};
定义一个广播接收器,接受设备连接蓝牙状态的一个广播:
mGattUpdateReceiver = new GattupdateReceiver(); mGattUpdateReceiver.setBluetoothConnetinteface(this); registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); public static IntentFilter makeGattUpdateIntentFilter() { // 注册接收的事件 final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter .addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); intentFilter.addAction(BluetoothDevice.ACTION_UUID); return intentFilter; }
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.util.Log; public class GattupdateReceiver extends BroadcastReceiver { public static String TAG = "GattupdateReceiver"; String data ; private BluetoothConnetListen mBluetoothConnetListen;//实现接口 private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: // 连接成功
if (mBluetoothConnetListen != null) { mBluetoothConnetListen.SuccessConnect(); } break; case 1: // 链接中断 if (mBluetoothConnetListen != null) { mBluetoothConnetListen.CancelConnect(); } break; case 2: // 可以进行数据通信
CoushionApplication.isconnect = true; if (mBluetoothConnetListen != null) { mBluetoothConnetListen.onDoThing(); } break; case 3: // 接受到数据 if (mBluetoothConnetListen != null) { mBluetoothConnetListen.ReceiveData(data); } break; } } }; public void setBluetoothConnetinteface(BluetoothConnetListen m) { mBluetoothConnetListen = m; } @Override public void onReceive(Context arg0, Intent intent) { // TODO Auto-generated method stub final String action = intent.getAction(); Log.d(TAG, "Action==" + action); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //连接成功 Log.e(TAG, "Only gatt, just wait"); mHandler.sendEmptyMessage(0); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { //连接失败 mHandler.sendEmptyMessage(1);
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED .equals(action)) //可以通信 { mHandler.sendEmptyMessage(2);
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //接受到数据 Log.e(TAG, "RECV DATA"); data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA); mHandler.sendEmptyMessage(3); } } }
在activity中实现接口后 BluetoothConnetListen。即可多蓝牙模块进行操作了。
mBluetoothLeService.WriteValue(edtSend.getText().toString());//向蓝牙发送指令或者数据
标签:
原文地址:http://www.cnblogs.com/zoff/p/5657349.html