[Bluetooth][TCSACR-221] Add BluetoothGattClient APIs (#712)
authorWootak <nonsan1228@gmail.com>
Mon, 11 Mar 2019 02:07:42 +0000 (11:07 +0900)
committerGitHub <noreply@github.com>
Mon, 11 Mar 2019 02:07:42 +0000 (11:07 +0900)
[Bluetooth][TCSACR-221] Add BluetoothGattClient APIs (#712)

src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothGatt.cs
src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothGattImpl.cs

index 5a40d27..a1c3134 100644 (file)
@@ -257,24 +257,168 @@ namespace Tizen.Network.Bluetooth
     /// The Bluetooth GATT client.
     /// </summary>
     /// <since_tizen> 3 </since_tizen>
-    public class BluetoothGattClient
+    public class BluetoothGattClient : IDisposable
     {
         private BluetoothGattClientImpl _impl;
         private string _remoteAddress = string.Empty;
+        private TaskCompletionSource<bool> _taskForConnection;
+        private TaskCompletionSource<bool> _taskForDisconnection;
+        private static event EventHandler<GattConnectionStateChangedEventArgs> s_connectionStateChanged;
+        private static Interop.Bluetooth.GattConnectionStateChangedCallBack s_connectionStateChangeCallback;
 
         internal BluetoothGattClient(string remoteAddress)
         {
             _impl = new BluetoothGattClientImpl(remoteAddress);
             _remoteAddress = remoteAddress;
+            StaticConnectionStateChanged += OnConnectionStateChanged;
         }
 
-        internal static BluetoothGattClient CreateClient(string remoteAddress)
+        /// <summary>
+        /// Creates the Bluetooth GATT client.
+        /// </summary>
+        /// <returns>The BluetoothGattClient instance.</returns>
+        /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
+        /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static BluetoothGattClient CreateClient(string remoteAddress)
         {
             BluetoothGattClient client = new BluetoothGattClient(remoteAddress);
             return client.Isvalid() ? client : null;
         }
 
         /// <summary>
+        /// The ConnectionStateChanged event is raised when the gatt connection state is changed.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public event EventHandler<GattConnectionStateChangedEventArgs> ConnectionStateChanged;
+
+        private void OnConnectionStateChanged(Object s, GattConnectionStateChangedEventArgs e)
+        {
+            if (e.RemoteAddress == _remoteAddress)
+            {
+                if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
+                {
+                    if (e.Result == (int)BluetoothError.None)
+                    {
+                        _taskForConnection.SetResult(true);
+                    }
+                    else
+                    {
+                        _taskForConnection.SetException(BluetoothErrorFactory.CreateBluetoothException((int)e.Result));
+                    }
+                    _taskForConnection = null;
+                }
+
+                if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
+                {
+                    if (e.Result == (int)BluetoothError.None)
+                    {
+                        _taskForDisconnection.SetResult(true);
+                    }
+                    else
+                    {
+                        _taskForDisconnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result));
+                    }
+                    _taskForDisconnection = null;
+                }
+
+                if (e.Result == (int)BluetoothError.None)
+                {
+                    ConnectionStateChanged?.Invoke(this, e);
+                }
+            }
+        }
+
+        private static event EventHandler<GattConnectionStateChangedEventArgs> StaticConnectionStateChanged
+        {
+            add
+            {
+                if (s_connectionStateChanged == null)
+                {
+                    RegisterConnectionStateChangedEvent();
+                }
+                s_connectionStateChanged += value;
+            }
+            remove
+            {
+                s_connectionStateChanged -= value;
+                if (s_connectionStateChanged == null)
+                {
+                    UnregisterConnectionStateChangedEvent();
+                }
+            }
+        }
+
+        private static void RegisterConnectionStateChangedEvent()
+        {
+            s_connectionStateChangeCallback = (int result, bool connected, string remoteDeviceAddress, IntPtr userData) =>
+            {
+                Log.Info(Globals.LogTag, "Setting gatt connection state changed callback");
+                GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs(result, connected, remoteDeviceAddress);
+                s_connectionStateChanged?.Invoke(null, e);
+            };
+
+            int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(s_connectionStateChangeCallback, IntPtr.Zero);
+            if (ret != (int)BluetoothError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret);
+                BluetoothErrorFactory.ThrowBluetoothException(ret);
+            }
+        }
+
+        private static void UnregisterConnectionStateChangedEvent()
+        {
+            int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback();
+            if (ret != (int)BluetoothError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret);
+                BluetoothErrorFactory.ThrowBluetoothException(ret);
+            }
+        }
+
+        /// <summary>
+        /// Connects to the remote GATT server asynchronously.
+        /// </summary>
+        /// <param name="autoConnect">The flag for reconnecting when the connection is disconnceted.</param>
+        /// <returns> A task indicating whether the method is done or not.</returns>
+        /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
+        /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
+        /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public Task ConnectAsync(bool autoConnect)
+        {
+            if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
+            {
+                BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
+            }
+            _taskForConnection = new TaskCompletionSource<bool>();
+            _impl.Connect(_remoteAddress, autoConnect);
+            return _taskForConnection.Task;
+        }
+
+        /// <summary>
+        /// Disconnects to the remote GATT server asynchronously.
+        /// </summary>
+        /// <returns> A task indicating whether the method is done or not.</returns>
+        /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
+        /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
+        /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public Task DisconnectAsync()
+        {
+            if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
+            {
+                BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
+            }
+            _taskForDisconnection = new TaskCompletionSource<bool>();
+            _impl.Disconnect(_remoteAddress);
+            return _taskForDisconnection.Task;
+        }
+
+        /// <summary>
         /// Destroy Bluetooth GATT client
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
@@ -382,6 +526,40 @@ namespace Tizen.Network.Bluetooth
         {
             return _impl.GetHandle().IsInvalid == false;
         }
+
+        /// <summary>
+        /// Destroys the current object.
+        /// </summary>
+        ~BluetoothGattClient()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Destroys the current object.
+        /// </summary>
+        /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
+        /// <since_tizen> 6 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Releases all the resources currently used by this instance.
+        /// </summary>
+        /// <param name="disposing">true if the managed resources should be disposed, otherwise false.</param>
+        /// <since_tizen> 6 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                _impl?.GetHandle()?.Dispose();
+                _impl = null;
+                StaticConnectionStateChanged -= OnConnectionStateChanged;
+            }
+        }
     }
 
     /// <summary>
index bf8b842..652326a 100644 (file)
@@ -143,8 +143,27 @@ namespace Tizen.Network.Bluetooth
 
         internal BluetoothGattClientImpl(string remoteAddress)
         {
-            int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
-            GattUtil.ThrowForError(err, "Failed to get native client handle");
+            if (BluetoothAdapter.IsBluetoothEnabled)
+            {
+                int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
+                GattUtil.ThrowForError(err, "Failed to get native client handle");
+            }
+            else
+            {
+                BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
+            }
+        }
+
+        internal void Connect(string remoteAddress, bool autoConnect)
+        {
+            int err = Interop.Bluetooth.GattConnect(remoteAddress, autoConnect);
+            GattUtil.ThrowForError(err, "Failed to connect to remote address");
+        }
+
+        internal void Disconnect(string remoteAddress)
+        {
+            int err = Interop.Bluetooth.GattDisconnect(remoteAddress);
+            GattUtil.ThrowForError(err, "Failed to disconnect to remote address");
         }
 
         internal string GetRemoteAddress()