PageRenderTime 41ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/BluetoothLeGatt/BluetoothLeService.cs

https://gitlab.com/muthuprabhu/monodroid-samples
C# | 341 lines | 221 code | 41 blank | 79 comment | 57 complexity | ea8e40276d63c977e16850630fad1bfe MD5 | raw file
  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. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Text;
  20. using Android.App;
  21. using Android.Content;
  22. using Android.OS;
  23. using Android.Runtime;
  24. using Android.Views;
  25. using Android.Widget;
  26. using Android.Bluetooth;
  27. using Java.Util;
  28. using Android.Util;
  29. namespace BluetoothLeGatt
  30. {
  31. /**
  32. * Service for managing connection and data communication with a GATT server hosted on a
  33. * given Bluetooth LE device.
  34. */
  35. [Service (Name = "bluetoothlegatt.BluetoothLeService", Enabled = true )]
  36. public class BluetoothLeService : Service
  37. {
  38. public readonly static String TAG = typeof (BluetoothLeService).Name;
  39. public static BluetoothManager mBluetoothManager;
  40. public static BluetoothAdapter mBluetoothAdapter;
  41. public static String mBluetoothDeviceAddress;
  42. public static BluetoothGatt mBluetoothGatt;
  43. public static State mConnectionState = State.Disconnected;
  44. public readonly static String ACTION_GATT_CONNECTED =
  45. "com.xamarin.bluetooth.le.ACTION_GATT_CONNECTED";
  46. public readonly static String ACTION_GATT_DISCONNECTED =
  47. "com.xamarin.bluetooth.le.ACTION_GATT_DISCONNECTED";
  48. public readonly static String ACTION_GATT_SERVICES_DISCOVERED =
  49. "com.xamarin.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
  50. public readonly static String ACTION_DATA_AVAILABLE =
  51. "com.xamarin.bluetooth.le.ACTION_DATA_AVAILABLE";
  52. public readonly static String EXTRA_DATA =
  53. "com.xamarin.bluetooth.le.EXTRA_DATA";
  54. public readonly static UUID UUID_HEART_RATE_MEASUREMENT =
  55. UUID.FromString (SampleGattAttributes.HEART_RATE_MEASUREMENT);
  56. IBinder mBinder;
  57. public void BroadcastUpdate (String action)
  58. {
  59. Intent intent = new Intent (action);
  60. SendBroadcast (intent);
  61. }
  62. public void BroadcastUpdate (String action, BluetoothGattCharacteristic characteristic)
  63. {
  64. Intent intent = new Intent (action);
  65. // This is special handling for the Heart Rate Measurement profile. Data parsing is
  66. // carried out as per profile specifications:
  67. // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
  68. if (UUID_HEART_RATE_MEASUREMENT == (characteristic.Uuid)) {
  69. GattProperty flag = characteristic.Properties;
  70. GattFormat format = (GattFormat) (-1);
  71. if (((int) flag & 0x01) != 0) {
  72. format = GattFormat.Uint16;
  73. Log.Debug (TAG, "Heart rate format UINT16.");
  74. } else {
  75. format = GattFormat.Uint8;
  76. Log.Debug (TAG, "Heart rate format UINT8.");
  77. }
  78. var heartRate = characteristic.GetIntValue (format, 1);
  79. Log.Debug (TAG, String.Format ("Received heart rate: {0}", heartRate));
  80. intent.PutExtra (EXTRA_DATA, heartRate);
  81. } else {
  82. // For all other profiles, writes the data formatted in HEX.
  83. byte[] data = characteristic.GetValue ();
  84. if (data != null && data.Length > 0) {
  85. StringBuilder stringBuilder = new StringBuilder (data.Length);
  86. foreach (byte byteChar in data)
  87. stringBuilder.Append (String.Format ("{0}02X ", byteChar));
  88. intent.PutExtra (EXTRA_DATA, Convert.ToBase64String (data) + "\n" + stringBuilder.ToString());
  89. }
  90. }
  91. SendBroadcast (intent);
  92. }
  93. public class LocalBinder : Binder
  94. {
  95. BluetoothLeService service;
  96. public LocalBinder (BluetoothLeService service)
  97. {
  98. this.service = service;
  99. }
  100. public BluetoothLeService GetService ()
  101. {
  102. return service;
  103. }
  104. }
  105. public override IBinder OnBind (Intent intent)
  106. {
  107. mBinder = new LocalBinder (this);
  108. return mBinder;
  109. }
  110. public override bool OnUnbind (Intent intent)
  111. {
  112. // After using a given device, you should make sure that BluetoothGatt.close() is called
  113. // such that resources are cleaned up properly. In this particular example, close() is
  114. // invoked when the UI is disconnected from the Service.
  115. Close ();
  116. return base.OnUnbind (intent);
  117. }
  118. /**
  119. * Initializes a reference to the local Bluetooth adapter.
  120. *
  121. * @return Return true if the initialization is successful.
  122. */
  123. public bool Initialize()
  124. {
  125. // For API level 18 and above, get a reference to BluetoothAdapter through
  126. // BluetoothManager.
  127. if (mBluetoothManager == null) {
  128. mBluetoothManager = (BluetoothManager) GetSystemService (Context.BluetoothService);
  129. if (mBluetoothManager == null) {
  130. Log.Error (TAG, "Unable to initialize BluetoothManager.");
  131. return false;
  132. }
  133. }
  134. mBluetoothAdapter = mBluetoothManager.Adapter;
  135. if (mBluetoothAdapter == null) {
  136. Log.Error (TAG, "Unable to obtain a BluetoothAdapter.");
  137. return false;
  138. }
  139. return true;
  140. }
  141. /**
  142. * Connects to the GATT server hosted on the Bluetooth LE device.
  143. *
  144. * @param address The device address of the destination device.
  145. *
  146. * @return Return true if the connection is initiated successfully. The connection result
  147. * is reported asynchronously through the
  148. * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
  149. * callback.
  150. */
  151. public bool Connect (String address)
  152. {
  153. if (mBluetoothAdapter == null || address == null) {
  154. Log.Warn (TAG, "BluetoothAdapter not initialized or unspecified address.");
  155. return false;
  156. }
  157. // Previously connected device. Try to reconnect.
  158. if (mBluetoothDeviceAddress != null && address == mBluetoothDeviceAddress && mBluetoothGatt != null) {
  159. Log.Debug (TAG, "Trying to use an existing mBluetoothGatt for connection.");
  160. if (mBluetoothGatt.Connect ()) {
  161. mConnectionState = State.Connecting;
  162. return true;
  163. } else {
  164. return false;
  165. }
  166. }
  167. BluetoothDevice device = mBluetoothAdapter.GetRemoteDevice (address);
  168. if (device == null) {
  169. Log.Warn (TAG, "Device not found. Unable to connect.");
  170. return false;
  171. }
  172. // We want to directly connect to the device, so we are setting the autoConnect
  173. // parameter to false.
  174. mBluetoothGatt = device.ConnectGatt (this, false, new BGattCallback (this));
  175. Log.Debug (TAG, "Trying to create a new connection.");
  176. mBluetoothDeviceAddress = address;
  177. mConnectionState = State.Connecting;
  178. return true;
  179. }
  180. /**
  181. * Disconnects an existing connection or cancel a pending connection. The disconnection result
  182. * is reported asynchronously through the
  183. * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
  184. * callback.
  185. */
  186. public void Disconnect ()
  187. {
  188. if (mBluetoothAdapter == null || mBluetoothGatt == null) {
  189. Log.Warn (TAG, "BluetoothAdapter not initialized");
  190. return;
  191. }
  192. mBluetoothGatt.Disconnect ();
  193. }
  194. /**
  195. * After using a given BLE device, the app must call this method to ensure resources are
  196. * released properly.
  197. */
  198. public void Close ()
  199. {
  200. if (mBluetoothGatt == null) {
  201. return;
  202. }
  203. mBluetoothGatt.Close ();
  204. mBluetoothGatt = null;
  205. }
  206. /**
  207. * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
  208. * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
  209. * callback.
  210. *
  211. * @param characteristic The characteristic to read from.
  212. */
  213. public void ReadCharacteristic (BluetoothGattCharacteristic characteristic)
  214. {
  215. if (mBluetoothAdapter == null || mBluetoothGatt == null) {
  216. Log.Warn (TAG, "BluetoothAdapter not initialized");
  217. return;
  218. }
  219. mBluetoothGatt.ReadCharacteristic (characteristic);
  220. }
  221. /**
  222. * Enables or disables notification on a give characteristic.
  223. *
  224. * @param characteristic Characteristic to act on.
  225. * @param enabled If true, enable notification. False otherwise.
  226. */
  227. public void SetCharacteristicNotification (BluetoothGattCharacteristic characteristic, bool enabled)
  228. {
  229. if (mBluetoothAdapter == null || mBluetoothGatt == null) {
  230. Log.Warn (TAG, "BluetoothAdapter not initialized");
  231. return;
  232. }
  233. mBluetoothGatt.SetCharacteristicNotification (characteristic, enabled);
  234. // This is specific to Heart Rate Measurement.
  235. if (UUID_HEART_RATE_MEASUREMENT == characteristic.Uuid) {
  236. BluetoothGattDescriptor descriptor = characteristic.GetDescriptor (
  237. UUID.FromString (SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
  238. descriptor.SetValue (BluetoothGattDescriptor.EnableNotificationValue.ToArray ());
  239. mBluetoothGatt.WriteDescriptor (descriptor);
  240. }
  241. }
  242. /**
  243. * Retrieves a list of supported GATT services on the connected device. This should be
  244. * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
  245. *
  246. * @return A {@code List} of supported services.
  247. */
  248. public IList <BluetoothGattService> GetSupportedGattServices ()
  249. {
  250. if (mBluetoothGatt == null) return null;
  251. return mBluetoothGatt.Services;
  252. }
  253. }
  254. // Implements callback methods for GATT events that the app cares about. For example,
  255. // connection change and services discovered.
  256. class BGattCallback : BluetoothGattCallback
  257. {
  258. BluetoothLeService service;
  259. public BGattCallback (BluetoothLeService s)
  260. {
  261. service = s;
  262. }
  263. public override void OnConnectionStateChange (BluetoothGatt gatt, GattStatus status, ProfileState newState)
  264. {
  265. String intentAction;
  266. if (newState == ProfileState.Connected) {
  267. intentAction = BluetoothLeService.ACTION_GATT_CONNECTED;
  268. BluetoothLeService.mConnectionState = State.Connected;
  269. service.BroadcastUpdate (intentAction);
  270. Log.Info (BluetoothLeService.TAG, "Connected to GATT server.");
  271. // Attempts to discover services after successful connection.
  272. Log.Info (BluetoothLeService.TAG, "Attempting to start service discovery:" +
  273. BluetoothLeService.mBluetoothGatt.DiscoverServices ());
  274. } else if (newState == ProfileState.Disconnected) {
  275. intentAction = BluetoothLeService.ACTION_GATT_DISCONNECTED;
  276. BluetoothLeService.mConnectionState = State.Disconnected;
  277. Log.Info (BluetoothLeService.TAG, "Disconnected from GATT server.");
  278. service.BroadcastUpdate (intentAction);
  279. }
  280. }
  281. public override void OnServicesDiscovered (BluetoothGatt gatt, GattStatus status)
  282. {
  283. if (status == GattStatus.Success) {
  284. service.BroadcastUpdate (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
  285. } else {
  286. Log.Warn (BluetoothLeService.TAG, "onServicesDiscovered received: " + status);
  287. }
  288. }
  289. public override void OnCharacteristicRead (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, GattStatus status)
  290. {
  291. if (status == GattStatus.Success) {
  292. service.BroadcastUpdate (BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
  293. }
  294. }
  295. public override void OnCharacteristicChanged (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
  296. {
  297. service.BroadcastUpdate (BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
  298. }
  299. }
  300. }