Skip to content

Commit 7ac2259

Browse files
committed
Added BLE Framework for Android and examples.
1 parent dbf8e72 commit 7ac2259

File tree

82 files changed

+4435
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+4435
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (C) 2013 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.redbear.simplecontrols;
18+
19+
import java.util.HashMap;
20+
21+
/**
22+
* This class includes a small subset of standard GATT attributes for
23+
* demonstration purposes.
24+
*/
25+
public class RBLGattAttributes {
26+
private static HashMap<String, String> attributes = new HashMap<String, String>();
27+
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
28+
public static String BLE_SHIELD_TX = "713d0003-503e-4c75-ba94-3148f18d941e";
29+
public static String BLE_SHIELD_RX = "713d0002-503e-4c75-ba94-3148f18d941e";
30+
public static String BLE_SHIELD_SERVICE = "713d0000-503e-4c75-ba94-3148f18d941e";
31+
32+
static {
33+
// RBL Services.
34+
attributes.put("713d0000-503e-4c75-ba94-3148f18d941e",
35+
"BLE Shield Service");
36+
// RBL Characteristics.
37+
attributes.put(BLE_SHIELD_TX, "BLE Shield TX");
38+
attributes.put(BLE_SHIELD_RX, "BLE Shield RX");
39+
}
40+
41+
public static String lookup(String uuid, String defaultName) {
42+
String name = attributes.get(uuid);
43+
return name == null ? defaultName : name;
44+
}
45+
}

BLEFramework/RBLService.java

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
/*
2+
* Copyright (C) 2013 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.redbear.simplecontrols;
18+
19+
import java.util.UUID;
20+
21+
import android.app.Service;
22+
import android.bluetooth.BluetoothAdapter;
23+
import android.bluetooth.BluetoothDevice;
24+
import android.bluetooth.BluetoothGatt;
25+
import android.bluetooth.BluetoothGattCallback;
26+
import android.bluetooth.BluetoothGattCharacteristic;
27+
import android.bluetooth.BluetoothGattDescriptor;
28+
import android.bluetooth.BluetoothGattService;
29+
import android.bluetooth.BluetoothManager;
30+
import android.bluetooth.BluetoothProfile;
31+
import android.content.Context;
32+
import android.content.Intent;
33+
import android.os.Binder;
34+
import android.os.IBinder;
35+
import android.util.Log;
36+
37+
/**
38+
* Service for managing connection and data communication with a GATT server
39+
* hosted on a given Bluetooth LE device.
40+
*/
41+
public class RBLService extends Service {
42+
private final static String TAG = RBLService.class.getSimpleName();
43+
44+
private BluetoothManager mBluetoothManager;
45+
private BluetoothAdapter mBluetoothAdapter;
46+
private String mBluetoothDeviceAddress;
47+
private BluetoothGatt mBluetoothGatt;
48+
49+
public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
50+
public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
51+
public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
52+
public final static String ACTION_GATT_RSSI = "ACTION_GATT_RSSI";
53+
public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
54+
public final static String EXTRA_DATA = "EXTRA_DATA";
55+
56+
public final static UUID UUID_BLE_SHIELD_TX = UUID
57+
.fromString(RBLGattAttributes.BLE_SHIELD_TX);
58+
public final static UUID UUID_BLE_SHIELD_RX = UUID
59+
.fromString(RBLGattAttributes.BLE_SHIELD_RX);
60+
public final static UUID UUID_BLE_SHIELD_SERVICE = UUID
61+
.fromString(RBLGattAttributes.BLE_SHIELD_SERVICE);
62+
63+
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
64+
@Override
65+
public void onConnectionStateChange(BluetoothGatt gatt, int status,
66+
int newState) {
67+
String intentAction;
68+
69+
if (newState == BluetoothProfile.STATE_CONNECTED) {
70+
intentAction = ACTION_GATT_CONNECTED;
71+
broadcastUpdate(intentAction);
72+
Log.i(TAG, "Connected to GATT server.");
73+
// Attempts to discover services after successful connection.
74+
Log.i(TAG, "Attempting to start service discovery:"
75+
+ mBluetoothGatt.discoverServices());
76+
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
77+
intentAction = ACTION_GATT_DISCONNECTED;
78+
Log.i(TAG, "Disconnected from GATT server.");
79+
broadcastUpdate(intentAction);
80+
}
81+
}
82+
83+
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
84+
if (status == BluetoothGatt.GATT_SUCCESS) {
85+
broadcastUpdate(ACTION_GATT_RSSI, rssi);
86+
} else {
87+
Log.w(TAG, "onReadRemoteRssi received: " + status);
88+
}
89+
};
90+
91+
@Override
92+
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
93+
if (status == BluetoothGatt.GATT_SUCCESS) {
94+
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
95+
} else {
96+
Log.w(TAG, "onServicesDiscovered received: " + status);
97+
}
98+
}
99+
100+
@Override
101+
public void onCharacteristicRead(BluetoothGatt gatt,
102+
BluetoothGattCharacteristic characteristic, int status) {
103+
if (status == BluetoothGatt.GATT_SUCCESS) {
104+
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
105+
}
106+
}
107+
108+
@Override
109+
public void onCharacteristicChanged(BluetoothGatt gatt,
110+
BluetoothGattCharacteristic characteristic) {
111+
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
112+
}
113+
};
114+
115+
private void broadcastUpdate(final String action) {
116+
final Intent intent = new Intent(action);
117+
sendBroadcast(intent);
118+
}
119+
120+
private void broadcastUpdate(final String action, int rssi) {
121+
final Intent intent = new Intent(action);
122+
intent.putExtra(EXTRA_DATA, String.valueOf(rssi));
123+
sendBroadcast(intent);
124+
}
125+
126+
private void broadcastUpdate(final String action,
127+
final BluetoothGattCharacteristic characteristic) {
128+
final Intent intent = new Intent(action);
129+
130+
// This is special handling for the Heart Rate Measurement profile. Data
131+
// parsing is
132+
// carried out as per profile specifications:
133+
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
134+
if (UUID_BLE_SHIELD_RX.equals(characteristic.getUuid())) {
135+
final byte[] rx = characteristic.getValue();
136+
intent.putExtra(EXTRA_DATA, rx);
137+
}
138+
139+
sendBroadcast(intent);
140+
}
141+
142+
public class LocalBinder extends Binder {
143+
RBLService getService() {
144+
return RBLService.this;
145+
}
146+
}
147+
148+
@Override
149+
public IBinder onBind(Intent intent) {
150+
return mBinder;
151+
}
152+
153+
@Override
154+
public boolean onUnbind(Intent intent) {
155+
// After using a given device, you should make sure that
156+
// BluetoothGatt.close() is called
157+
// such that resources are cleaned up properly. In this particular
158+
// example, close() is
159+
// invoked when the UI is disconnected from the Service.
160+
close();
161+
return super.onUnbind(intent);
162+
}
163+
164+
private final IBinder mBinder = new LocalBinder();
165+
166+
/**
167+
* Initializes a reference to the local Bluetooth adapter.
168+
*
169+
* @return Return true if the initialization is successful.
170+
*/
171+
public boolean initialize() {
172+
// For API level 18 and above, get a reference to BluetoothAdapter
173+
// through
174+
// BluetoothManager.
175+
if (mBluetoothManager == null) {
176+
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
177+
if (mBluetoothManager == null) {
178+
Log.e(TAG, "Unable to initialize BluetoothManager.");
179+
return false;
180+
}
181+
}
182+
183+
mBluetoothAdapter = mBluetoothManager.getAdapter();
184+
if (mBluetoothAdapter == null) {
185+
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
186+
return false;
187+
}
188+
189+
return true;
190+
}
191+
192+
/**
193+
* Connects to the GATT server hosted on the Bluetooth LE device.
194+
*
195+
* @param address
196+
* The device address of the destination device.
197+
*
198+
* @return Return true if the connection is initiated successfully. The
199+
* connection result is reported asynchronously through the
200+
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
201+
* callback.
202+
*/
203+
public boolean connect(final String address) {
204+
if (mBluetoothAdapter == null || address == null) {
205+
Log.w(TAG,
206+
"BluetoothAdapter not initialized or unspecified address.");
207+
return false;
208+
}
209+
210+
// Previously connected device. Try to reconnect.
211+
if (mBluetoothDeviceAddress != null
212+
&& address.equals(mBluetoothDeviceAddress)
213+
&& mBluetoothGatt != null) {
214+
Log.d(TAG,
215+
"Trying to use an existing mBluetoothGatt for connection.");
216+
if (mBluetoothGatt.connect()) {
217+
return true;
218+
} else {
219+
return false;
220+
}
221+
}
222+
223+
final BluetoothDevice device = mBluetoothAdapter
224+
.getRemoteDevice(address);
225+
if (device == null) {
226+
Log.w(TAG, "Device not found. Unable to connect.");
227+
return false;
228+
}
229+
// We want to directly connect to the device, so we are setting the
230+
// autoConnect
231+
// parameter to false.
232+
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
233+
Log.d(TAG, "Trying to create a new connection.");
234+
mBluetoothDeviceAddress = address;
235+
236+
return true;
237+
}
238+
239+
/**
240+
* Disconnects an existing connection or cancel a pending connection. The
241+
* disconnection result is reported asynchronously through the
242+
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
243+
* callback.
244+
*/
245+
public void disconnect() {
246+
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
247+
Log.w(TAG, "BluetoothAdapter not initialized");
248+
return;
249+
}
250+
mBluetoothGatt.disconnect();
251+
}
252+
253+
/**
254+
* After using a given BLE device, the app must call this method to ensure
255+
* resources are released properly.
256+
*/
257+
public void close() {
258+
if (mBluetoothGatt == null) {
259+
return;
260+
}
261+
mBluetoothGatt.close();
262+
mBluetoothGatt = null;
263+
}
264+
265+
/**
266+
* Request a read on a given {@code BluetoothGattCharacteristic}. The read
267+
* result is reported asynchronously through the
268+
* {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
269+
* callback.
270+
*
271+
* @param characteristic
272+
* The characteristic to read from.
273+
*/
274+
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
275+
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
276+
Log.w(TAG, "BluetoothAdapter not initialized");
277+
return;
278+
}
279+
280+
mBluetoothGatt.readCharacteristic(characteristic);
281+
}
282+
283+
public void readRssi() {
284+
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
285+
Log.w(TAG, "BluetoothAdapter not initialized");
286+
return;
287+
}
288+
289+
mBluetoothGatt.readRemoteRssi();
290+
}
291+
292+
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
293+
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
294+
Log.w(TAG, "BluetoothAdapter not initialized");
295+
return;
296+
}
297+
298+
mBluetoothGatt.writeCharacteristic(characteristic);
299+
}
300+
301+
/**
302+
* Enables or disables notification on a give characteristic.
303+
*
304+
* @param characteristic
305+
* Characteristic to act on.
306+
* @param enabled
307+
* If true, enable notification. False otherwise.
308+
*/
309+
public void setCharacteristicNotification(
310+
BluetoothGattCharacteristic characteristic, boolean enabled) {
311+
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
312+
Log.w(TAG, "BluetoothAdapter not initialized");
313+
return;
314+
}
315+
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
316+
317+
if (UUID_BLE_SHIELD_RX.equals(characteristic.getUuid())) {
318+
BluetoothGattDescriptor descriptor = characteristic
319+
.getDescriptor(UUID
320+
.fromString(RBLGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
321+
descriptor
322+
.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
323+
mBluetoothGatt.writeDescriptor(descriptor);
324+
}
325+
}
326+
327+
public BluetoothGattService getSupportedGattService() {
328+
if (mBluetoothGatt == null)
329+
return null;
330+
331+
return mBluetoothGatt.getService(UUID_BLE_SHIELD_SERVICE);
332+
}
333+
}

0 commit comments

Comments
 (0)