1 |
public class BluetoothLeService extends Service{ |
2 |
private static final String TAG=”BluetoothLeService”; //这里是用来打印的 |
3 |
private String mBluetoothDeviceAddress; //蓝牙地址 |
4 |
private BluetoothManager mBluetoothManager; //通过BluetoothManager来获取BluetoothAdapter |
5 |
private BluetoothGatt mBluetoothGatt; //通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback |
6 |
|
7 |
//常用的广播 |
8 |
public final static String ACTION_GATT_CONNECTED = “com.example.bluetooth.le.ACTION_GATT_CONNECTED”; //连接 |
9 |
public final static String ACTION_GATT_DISCONNECTED = “com.example.bluetooth.le.ACTION_GATT_DISCONNECTED”; //断开链接 |
10 |
public final static String ACTION_GATT_SERVICES_DISCOVERED = “com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED”; //发现设备 |
11 |
public final static String ACTION_DATA_AVAILABLE = “com.example.bluetooth.le.ACTION_DATA_AVAILABLE”; //官方的demo里面有这四个 |
12 |
//这2个是我自己需要读取的所以增加了 |
13 |
public final static String EXTRA_DATA = “com.example.bluetooth.le.EXTRA_DATA”; //有数据的时候传输数据 |
14 |
|
15 |
public final static String EXTRA_DATA_TEMP = “com.example.bluetooth.le.EXTRA_DATA_TEMP”; //温度类型变量 |
16 |
|
17 |
private BluetoothAdapter mBluetoothAdapter = null; |
18 |
|
19 |
private ArrayList<BluetoothGatt> connectionQueue = new ArrayList<BluetoothGatt>(); //创建一个BluetoothGatt的队列 |
20 |
//相当于一个数据类型,它包括一个value和0~n个value的描述(BluetoothGattDescriptor) |
21 |
public BluetoothGattCharacteristic mNotifyCharacteristic; |
22 |
|
23 |
private Context mContext; //上下文 |
24 |
|
25 |
//查找服务 |
26 |
public void findService(BluetoothGatt gatt){ |
27 |
List<BluetoothGattService> gattservices = gatt.getServices(); |
28 |
Log.i(TAG,”Count is:”+gattservices.size()); |
29 |
for(BluetoothGattService gattservice : gattservices){ |
30 |
Log.i(TAG,gattservice.getUuid().toString()); |
31 |
//如果服务要等于温度服务 |
32 |
if(gattservice.getUuid().toString().equalsIgnoreCase(GattAttributes.HEALTH_THERMO_SERVICE)){ |
33 |
List<BluetoothGattCharacteristic> gattCharacteristics = gattservice.getCharacteristics(); |
34 |
Log.i(TAG,”Count is:”+gattCharacteristics.size()); |
35 |
|
36 |
|
37 |
for(BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics){ |
38 |
String uuidchara = gattCharacteristic.getUuid().toString(); |
39 |
//如果是温度计的类型的话 |
40 |
/** |
41 |
注意:这里的GattAttributes 这个值相当于 |
42 |
//实际用你们自己的 |
43 |
public static final String HEALTH_TEMP_MEASUREMENT = “0000xxxx-0000-1000-8000-00805f9b34fb”; |
44 |
*/ |
45 |
if(uuidchara.equalsIgnoreCase(GattAttributes.TEMPERATURE_TYPE)){ |
46 |
prepareBroadcastDataRead(gattCharacteristic); |
47 |
} |
48 |
|
49 |
//如果是温度计的度数的时候 |
50 |
else if(uuidchara.equalsIgnoreCase(GattAttributes.HEALTH_TEMP_MEASUREMENT)){ |
51 |
prepareBroadcastDataIndicate(gattCharacteristic); |
52 |
|
53 |
//发现服务获取设备的地址 |
54 |
brocastUpdate(ACTION_GATT_SERVICES_DISCOVERED, gatt.getDevice().getAddress()); |
55 |
} |
56 |
} |
57 |
} |
58 |
} |
59 |
|
60 |
|
61 |
} |
62 |
|
63 |
/** |
64 |
* *重要的回调 |
65 |
*/ |
66 |
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { |
67 |
|
68 |
@Override |
69 |
public void onConnectionStateChange(BluetoothGatt gatt,int status,int newState){ |
70 |
String initAction; |
71 |
Log.i(TAG,”oldStatus = “+status+”NewStates”+newState); //打印出来 |
72 |
if(status == BluetoothGatt.GATT_SUCCESS){ //这个值一般返回的为0 |
73 |
//如果连接成功 |
74 |
if(newState == BluetoothProfile.STATE_CONNECTED){ |
75 |
initAction = ACTION_GATT_CONNECTED; |
76 |
|
77 |
brocastUpdate(initAction); |
78 |
|
79 |
//连接之后马上去发现服务 |
80 |
gatt.discoverServices(); |
81 |
} |
82 |
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){ //断开连接 |
83 |
initAction = ACTION_GATT_DISCONNECTED; |
84 |
|
85 |
brocastUpdate(initAction, gatt.getDevice().getAddress()); |
86 |
} |
87 |
|
88 |
} |
89 |
|
90 |
@Override |
91 |
public void onServicesDiscovered(BluetoothGatt gatt, int status) { |
92 |
if(status == BluetoothGatt.GATT_SUCCESS){ |
93 |
Log.w(TAG, “onServicesDiscovered received: ” + status); |
94 |
findService(gatt); |
95 |
}else{ |
96 |
if(gatt.getDevice().getUuids() == null){ |
97 |
Log.w(TAG, “onServicesDiscovered received: ” + status); |
98 |
} |
99 |
} |
100 |
}; |
101 |
//这个是读取数据 |
102 |
@Override |
103 |
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { |
104 |
if(status == BluetoothGatt.GATT_SUCCESS){ |
105 |
brocastUpdate(ACTION_DATA_AVAILABLE, characteristic); |
106 |
} |
107 |
}; |
108 |
|
109 |
//当数据发生改变的时候 |
110 |
@Override |
111 |
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { |
112 |
|
113 |
brocastUpdate(ACTION_DATA_AVAILABLE, characteristic); |
114 |
|
115 |
}; |
116 |
//写入数据 |
117 |
@Override |
118 |
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { |
119 |
|
120 |
if (status == BluetoothGatt.GATT_SUCCESS) { |
121 |
System.out.println(“onDescriptorWriteonDescriptorWrite = ” + status + “, descriptor =” + descriptor.getUuid().toString()); |
122 |
} |
123 |
}; |
124 |
}; |
125 |
|
126 |
|
127 |
|
128 |
|
129 |
/** |
130 |
* 接收广播可读的特征 |
131 |
*/ |
132 |
public void prepareBroadcastDataRead(BluetoothGattCharacteristic gattCharacteristic){ |
133 |
if((gattCharacteristic.getProperties()|BluetoothGattCharacteristic.PROPERTY_READ)>0){ |
134 |
readCharacteristic(gattCharacteristic); //当特征为可读的特征的时候就直接可以读取 |
135 |
} |
136 |
} |
137 |
|
138 |
/** |
139 |
* 接收广播通知特性 |
140 |
*/ |
141 |
public void prepareBroadcastDataIndicate(BluetoothGattCharacteristic gattCharacteristic){ |
142 |
if((gattCharacteristic.getProperties()|BluetoothGattCharacteristic.PROPERTY_INDICATE)>0){ |
143 |
setCharacteristicIndication(gattCharacteristic, |
144 |
true); //当特征为不可读的时候哪么就是为通知 |
145 |
} |
146 |
} |
147 |
|
148 |
/** |
149 |
* 处理连接蓝牙后进入这里面操作 |
150 |
*/ |
151 |
private final IBinder mBinder = new LocalBinder(); |
152 |
|
153 |
public class LocalBinder extends Binder{ |
154 |
public TemperatureServices getService(){ |
155 |
return TemperatureServices.this; |
156 |
} |
157 |
} |
158 |
|
159 |
|
160 |
@Override |
161 |
public IBinder onBind(Intent intent) { |
162 |
// TODO Auto-generated method stub |
163 |
return mBinder; |
164 |
} |
165 |
|
166 |
@Override |
167 |
public boolean onUnbind(Intent intent) { |
168 |
// After using a given device, you should make sure that BluetoothGatt.close() is called |
169 |
// such that resources are cleaned up properly. In this particular example, close() is |
170 |
// invoked when the UI is disconnected from the Service. |
171 |
close(); |
172 |
return super.onUnbind(intent); |
173 |
} |
174 |
|
175 |
|
176 |
/** |
177 |
* 对外事件处理类 |
178 |
* 更新广播事件 |
179 |
*/ |
180 |
private void brocastUpdate(final String action){ |
181 |
final Intent intent = new Intent(action); |
182 |
sendBroadcast(intent); |
183 |
} |
184 |
|
185 |
/** |
186 |
* 传地址广播 |
187 |
* @param action |
188 |
* @param strAddress |
189 |
*/ |
190 |
private void brocastUpdate(final String action,final String strAddress){ |
191 |
final Intent intent = new Intent(action); |
192 |
intent.putExtra(“DEVICE_ADDRESS”, strAddress); |
193 |
sendBroadcast(intent); |
194 |
} |
195 |
|
196 |
private void brocastUpdate(final String action,final BluetoothGattCharacteristic characteristic){ |
197 |
final Intent intent = new Intent(action); |
198 |
|
199 |
//当温度计为温度类型的时候 |
200 |
if(characteristic.getUuid().equals(UUIDDatabase.UUID_HEALTH_THERMOMETER_SENSOR_LOCATION)){ |
201 |
String a = HTMParser.getHealthThermoSensorLocation(characteristic, mContext); |
202 |
intent.putExtra(EXTRA_DATA, a); |
203 |
} |
204 |
|
205 |
else if(characteristic.getUuid().equals(UUIDDatabase.UUID_HEALTH_THERMOMETER)){ |
206 |
String health_temp = HTMParser.getHealthThermo(characteristic, mContext); |
207 |
intent.putExtra(EXTRA_DATA_TEMP, health_temp); |
208 |
} |
209 |
|
210 |
sendBroadcast(intent); |
211 |
} |
212 |
|
213 |
/** |
214 |
* 初始化一个参考本地蓝牙适配器 |
215 |
* @return |
216 |
*/ |
217 |
public boolean initialize(){ |
218 |
if(mBluetoothManager == null){ |
219 |
mBluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); |
220 |
if(mBluetoothManager == null){ |
221 |
Log.e(TAG,”Unable to initialize BluetoothManager.”); |
222 |
return false; |
223 |
} |
224 |
} |
225 |
|
226 |
mBluetoothAdapter = mBluetoothManager.getAdapter(); |
227 |
if(mBluetoothAdapter == null){ |
228 |
Log.e(TAG, “Unable to obtain a BluetoothAdapter.”); |
229 |
return false; |
230 |
} |
231 |
|
232 |
return true; |
233 |
} |
234 |
|
235 |
|
236 |
/** |
237 |
* 连接代码 |
238 |
* @param address |
239 |
* @param context |
240 |
* @return |
241 |
*/ |
242 |
public boolean connect(final String address,Context context){ |
243 |
mContext = context; |
244 |
if(mBluetoothAdapter == null && address == null){ |
245 |
Log.w(TAG, “BluetoothAdapter not initialized or unspecified address.”); |
246 |
return false; |
247 |
} |
248 |
|
249 |
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); |
250 |
|
251 |
if(device == null){ |
252 |
Log.w(TAG,”Device not found. Unable to connect.”); |
253 |
return false; |
254 |
} |
255 |
|
256 |
BluetoothGatt bluetoothGatt; |
257 |
|
258 |
bluetoothGatt = device.connectGatt(mContext, false, mGattCallback); |
259 |
if(checkGatt(bluetoothGatt)){ |
260 |
connectionQueue.add(bluetoothGatt); |
261 |
} |
262 |
|
263 |
Log.d(TAG, “Trying to create a new connection.”); |
264 |
|
265 |
return true; |
266 |
|
267 |
|
268 |
} |
269 |
|
270 |
/** |
271 |
* 检查是否加入了相同的特征 如果相同就移除掉 |
272 |
* @param bluetoothGatt |
273 |
* @return |
274 |
*/ |
275 |
private boolean checkGatt(BluetoothGatt bluetoothGatt){ |
276 |
if(!connectionQueue.isEmpty()){ |
277 |
for(BluetoothGatt btg:connectionQueue){ |
278 |
if(btg.equals(bluetoothGatt)){ |
279 |
return false; |
280 |
} |
281 |
} |
282 |
} |
283 |
|
284 |
return true; |
285 |
} |
286 |
|
287 |
/** |
288 |
* 断开蓝牙连接 一按断开是全部都断开 |
289 |
*/ |
290 |
public void disConnect(){ |
291 |
if(mBluetoothAdapter == null && connectionQueue.isEmpty()){ |
292 |
Log.w(TAG, “BluetoothAdapter not initialized”); |
293 |
return; |
294 |
} |
295 |
|
296 |
for(BluetoothGatt bluetoothGatt:connectionQueue){ |
297 |
bluetoothGatt.disconnect(); |
298 |
} |
299 |
} |
300 |
|
301 |
public void close(){ |
302 |
if(connectionQueue.isEmpty()){ |
303 |
return; |
304 |
} |
305 |
|
306 |
listClose(null); |
307 |
} |
308 |
|
309 |
/** |
310 |
* 清除连接蓝牙的数据 |
311 |
* 我这里用的是连接多台的设备,所以清除的时候需要一个一个的移除掉 |
312 |
* @param gatt |
313 |
*/ |
314 |
private synchronized void listClose(BluetoothGatt gatt){ |
315 |
if(!connectionQueue.isEmpty()){ |
316 |
if(gatt!=null){ |
317 |
for(final BluetoothGatt bluetoothGatt:connectionQueue){ |
318 |
if(bluetoothGatt.equals(gatt)){ |
319 |
bluetoothGatt.close(); |
320 |
|
321 |
new Thread(new Runnable() { |
322 |
|
323 |
@Override |
324 |
public void run() { |
325 |
try{ |
326 |
Thread.sleep(250); |
327 |
connectionQueue.remove(bluetoothGatt); |
328 |
|
329 |
}catch(Exception ex){ |
330 |
ex.printStackTrace(); |
331 |
} |
332 |
|
333 |
} |
334 |
}).start(); |
335 |
} |
336 |
} |
337 |
}else{ |
338 |
for(BluetoothGatt bluetoothGatt:connectionQueue){ |
339 |
bluetoothGatt.close(); |
340 |
} |
341 |
|
342 |
connectionQueue.clear(); |
343 |
} |
344 |
} |
345 |
} |
346 |
|
347 |
/** |
348 |
* 读取蓝牙数据 |
349 |
*/ |
350 |
public void readCharacteristic(BluetoothGattCharacteristic characteristic) { |
351 |
if (mBluetoothAdapter == null || connectionQueue.isEmpty()) { |
352 |
Log.w(TAG, “BluetoothAdapter not initialized”); |
353 |
return; |
354 |
} |
355 |
for (BluetoothGatt bluetoothGatt : connectionQueue) { |
356 |
bluetoothGatt.readCharacteristic(characteristic); |
357 |
} |
358 |
} |
359 |
|
360 |
/** |
361 |
* Enables or disables notification on a give characteristic. |
362 |
* |
363 |
* @param characteristic Characteristic to act on. |
364 |
* @param enabled If true, enable notification. False otherwise. |
365 |
*/ |
366 |
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, |
367 |
boolean enabled) { |
368 |
if (mBluetoothAdapter == null || connectionQueue.isEmpty()) { |
369 |
Log.w(TAG, “BluetoothAdapter not initialized”); |
370 |
return; |
371 |
} |
372 |
|
373 |
for(BluetoothGatt bluetoothGatt:connectionQueue){ |
374 |
bluetoothGatt.setCharacteristicNotification(characteristic, enabled); |
375 |
} |
376 |
} |
377 |
|
378 |
/** |
379 |
* 蓝牙温度计*关键的一步 有些特征只能通过这个 读取 并启用通知更新数据 |
380 |
* Enables or disables indications on a give characteristic. |
381 |
* 启用或禁用一个给定特性的指示 |
382 |
* @param characteristic Characteristic to act on. |
383 |
* @param enabled If true, enable indications. False otherwise. |
384 |
*/ |
385 |
public void setCharacteristicIndication( |
386 |
BluetoothGattCharacteristic characteristic, boolean enabled) { |
387 |
String serviceUUID = characteristic.getService().getUuid().toString(); |
388 |
|
389 |
String characteristicUUID = characteristic.getUuid().toString(); |
390 |
|
391 |
Log.i(“==TAG==”,serviceUUID+” “+characteristicUUID); |
392 |
|
393 |
for(BluetoothGatt mBluetoothGatt:connectionQueue){ |
394 |
|
395 |
if (mBluetoothAdapter == null || mBluetoothGatt == null) { |
396 |
return; |
397 |
} |
398 |
|
399 |
if (characteristic.getDescriptor(UUID |
400 |
.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG)) != null) { |
401 |
if (enabled == true) { |
402 |
BluetoothGattDescriptor descriptor = characteristic |
403 |
.getDescriptor(UUID |
404 |
.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); |
405 |
descriptor |
406 |
.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); |
407 |
mBluetoothGatt.writeDescriptor(descriptor); |
408 |
|
409 |
} else { |
410 |
BluetoothGattDescriptor descriptor = characteristic |
411 |
.getDescriptor(UUID |
412 |
.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); |
413 |
descriptor |
414 |
.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); |
415 |
mBluetoothGatt.writeDescriptor(descriptor); |
416 |
|
417 |
} |
418 |
} |
419 |
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); |
420 |
} |
421 |
} |
422 |
|
423 |
|
424 |
} |
|
|