From 01454c7212b70aeee10187b30d141c865285c0c0 Mon Sep 17 00:00:00 2001 From: Wootak Date: Thu, 13 Dec 2018 09:45:27 +0900 Subject: [PATCH] [Bluetooth] Add BluetoothHidDevice APIs (#574) [Bluetooth] Add BluetoothHidDevice APIs - Interop - BluetoothEnumerations - BluetoothData - BluetoothEventArgs --- .../Interop/Interop.Bluetooth.cs | 34 +++- .../Tizen.Network.Bluetooth/BluetoothData.cs | 143 +++++++++++++++ .../Tizen.Network.Bluetooth/BluetoothDevice.cs | 34 +--- .../BluetoothEnumerations.cs | 59 ++++++ .../Tizen.Network.Bluetooth/BluetoothError.cs | 106 ++++++----- .../Tizen.Network.Bluetooth/BluetoothEventArgs.cs | 71 +++++++ .../Tizen.Network.Bluetooth/BluetoothHidDevice.cs | 204 +++++++++++++++++++++ .../BluetoothHidDeviceImpl.cs | 178 ++++++++++++++++++ .../Tizen.Network.Bluetooth/BluetoothStructs.cs | 11 ++ 9 files changed, 754 insertions(+), 86 deletions(-) create mode 100644 src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDevice.cs create mode 100644 src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDeviceImpl.cs diff --git a/src/Tizen.Network.Bluetooth/Interop/Interop.Bluetooth.cs b/src/Tizen.Network.Bluetooth/Interop/Interop.Bluetooth.cs index d062b4e..9d2e737 100755 --- a/src/Tizen.Network.Bluetooth/Interop/Interop.Bluetooth.cs +++ b/src/Tizen.Network.Bluetooth/Interop/Interop.Bluetooth.cs @@ -62,9 +62,6 @@ internal static partial class Interop internal delegate void AudioConnectionStateChangedCallback(int result, bool connected, string deviceAddress, int profileType, IntPtr userData); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate void HidConnectionStateChangedCallback(int result, bool connected, string deviceAddress, IntPtr userData); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void ConnectionRequestedCallback(string deviceAddress, IntPtr userData); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void PushRequestedCallback(string file, long size, IntPtr userData); @@ -376,17 +373,42 @@ internal static partial class Interop [DllImport(Libraries.Bluetooth, EntryPoint = "bt_audio_unset_connection_state_changed_cb")] internal static extern int UnsetAudioConnectionStateChangedCallback(); - //Bluetooth Hid + // Bluetooth Hid + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void HidConnectionStateChangedCallback(int result, bool connected, string deviceAddress, IntPtr userData); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void HidDeviceConnectionStateChangedCallback(int result, bool connected, string deviceAddress, IntPtr userData); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void HidDeviceDataReceivedCallback(ref BluetoothHidDeviceReceivedDataStruct receivedData, IntPtr userData); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_host_initialize")] internal static extern int InitializeHid(HidConnectionStateChangedCallback hidConnectionChangedCb, IntPtr userData); [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_host_deinitialize")] internal static extern int DeinitializeHid(); - [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_host_connect")] internal static extern int Connect(string deviceAddress); [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_host_disconnect")] internal static extern int Disconnect(string deviceAddress); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_activate")] + internal static extern int ActivateHidDevice(HidDeviceConnectionStateChangedCallback stateChangedCb, IntPtr userData); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_deactivate")] + internal static extern int DeactivateHidDevice(); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_connect")] + internal static extern int ConnectHidDevice(string deviceAddress); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_disconnect")] + internal static extern int DisconnectHidDevice(string deviceAddress); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_send_mouse_event")] + internal static extern int SendHidDeviceMouseEvent(string deviceAddress, BluetoothHidMouseData mouseData); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_send_key_event")] + internal static extern int SendHidDeviceKeyEvent(string deviceAddress, BluetoothHidKeyData keyData); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_set_data_received_cb")] + internal static extern int SetHidDeviceDataReceivedCallback(HidDeviceDataReceivedCallback dataReceivedCb, IntPtr userData); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_unset_data_received_cb")] + internal static extern int UnsetHidDeviceDataReceivedCallback(); + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_hid_device_reply_to_report")] + internal static extern int ReplyToReportHidDevice(string deviceAddress, BluetoothHidHeaderType headerType, BluetoothHidParamType paramType, byte[] value, int len, IntPtr userData); + // Bluetooth OPP // Opp Server [DllImport(Libraries.Bluetooth, EntryPoint = "bt_opp_server_initialize")] @@ -414,7 +436,7 @@ internal static partial class Interop [DllImport(Libraries.Bluetooth, EntryPoint = "bt_opp_client_initialize")] internal static extern int InitializeOppClient(); - [DllImport(Libraries.Bluetooth, EntryPoint = "bt_opp_client_dinitialize")] + [DllImport(Libraries.Bluetooth, EntryPoint = "bt_opp_client_deinitialize")] internal static extern int DeinitializeOppClient(); [DllImport(Libraries.Bluetooth, EntryPoint = "bt_opp_client_add_file")] diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothData.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothData.cs index e3015d0..6bf97b5 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothData.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothData.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; namespace Tizen.Network.Bluetooth { @@ -542,4 +543,146 @@ namespace Tizen.Network.Bluetooth } } } + + /// + /// This class contains the HID mouse event information. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class BluetoothHidMouseData + { + /// + /// The button values, we can combine key's values when we pressed multiple mouse buttons + /// + /// 6 + public int Buttons + { + get; + set; + } + + /// + /// The location's x value, -128 ~127 + /// + /// 6 + public int AxisX + { + get; + set; + } + + /// + /// The location's y value, -128 ~127 + /// + /// 6 + public int AxisY + { + get; + set; + } + + /// + /// The padding value, -128 ~127 + /// + /// 6 + public int Padding + { + get; + set; + } + } + + /// + /// This class contains the HID keyboard event information. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class BluetoothHidKeyData + { + /// + /// The modifier keys : such as shift, alt + /// + /// 6 + public byte Modifier + { + get; + set; + } + + /// + /// The key value - currently pressed keys : Max 8 at once + /// + /// 6 + public byte[] Key + { + get; + set; + } + } + + /// + /// This class contains the data received from the HID Host. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class BluetoothHidDeviceReceivedData + { + /// + /// The default constructor. Initializes an object of the BluetoothHidReceivedData. + /// + /// 6 + internal static BluetoothHidDeviceReceivedData Create(BluetoothHidDeviceReceivedDataStruct structInfo) + { + BluetoothHidDeviceReceivedData receivedData = new BluetoothHidDeviceReceivedData(); + receivedData.Address = structInfo.RemoteAddress; + receivedData.HeaderType = structInfo.headerType; + receivedData.ParamType = structInfo.paramType; + if (structInfo.dataSize > 0) + { + receivedData.Data = new byte[structInfo.dataSize]; + Marshal.Copy(structInfo.data, receivedData.Data, 0, structInfo.dataSize); + } + return receivedData; + } + + /// + /// The remote device's address + /// + /// 6 + public string Address + { + get; + private set; + } + + /// + /// The header type + /// + /// 6 + public BluetoothHidHeaderType HeaderType + { + get; + private set; + } + + /// + /// The parameter type + /// + /// 6 + public BluetoothHidParamType ParamType + { + get; + private set; + } + + /// + /// The received data + /// + /// 6 + public byte[] Data + { + get; + private set; + } + } } diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothDevice.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothDevice.cs index 1a06057..34894a0 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothDevice.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothDevice.cs @@ -679,37 +679,9 @@ namespace Tizen.Network.Bluetooth /// 3 public T GetProfile() where T : BluetoothProfile { - /* - * FIXME: Find a proper way for dynamic allocation. - */ - T profile = null; - String type = typeof(T).ToString(); - if (type.Equals("Tizen.Network.Bluetooth.BluetoothAudio")) - { - BluetoothAudio audio = new BluetoothAudio(); - profile = (audio as T); - } - else if (type.Equals("Tizen.Network.Bluetooth.BluetoothAvrcp")) - { - BluetoothAvrcp avrcp = new BluetoothAvrcp(); - profile = (avrcp as T); - } - else if (type.Equals("Tizen.Network.Bluetooth.BluetoothHid")) - { - BluetoothHid hid = new BluetoothHid(); - profile = (hid as T); - } - - else if (type.Equals("Tizen.Network.Bluetooth.BluetoothOppClient")) - { - BluetoothOppClient oppClient = new BluetoothOppClient(); - profile = (oppClient as T); - } - - if (profile != null) - { - profile.RemoteAddress = RemoteDeviceAddress; - } + // TODO : Need to check capability of supporting profiles + var profile = Activator.CreateInstance(); + profile.RemoteAddress = RemoteDeviceAddress; return profile; } diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEnumerations.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEnumerations.cs index ac2fca9..b3b6a66 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEnumerations.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEnumerations.cs @@ -16,6 +16,7 @@ using System; using Tizen.Internals.Errors; +using System.ComponentModel; namespace Tizen.Network.Bluetooth { @@ -1232,4 +1233,62 @@ namespace Tizen.Network.Bluetooth /// Write = 1, } + + /// + /// Enumeration for the Bluetooth HID header type. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public enum BluetoothHidHeaderType + { + /// + /// The Bluetooth HID header type: Handshake + /// + Handshake, + /// + /// The Bluetooth HID header type: HID control + /// + HidControl, + /// + /// The Bluetooth HID header type: Get report + /// + GetReport, + /// + /// The Bluetooth HID header type: Set report + /// + SetReport, + /// + /// The Bluetooth HID header type: Get protocol + /// + GetProtocol, + /// + /// The Bluetooth HID header type: Set protocol + /// + SetProtocol, + /// + /// The Bluetooth HID header type: Data + /// + Data, + /// + /// The Bluetooth HID header type: Unknown + /// + Unknown + } + + /// + /// Enumeration for the Bluetooth HID parameter type. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public enum BluetoothHidParamType + { + /// + /// Parameter type: Input + /// + Input, + /// + /// Parameter type: Output + /// + Output + } } diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothError.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothError.cs index 83ce73d..3f245d9 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothError.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothError.cs @@ -27,82 +27,90 @@ namespace Tizen.Network.Bluetooth /// Exceptions for Bluetooth Errors. /// /// Thrown when the Bluetooth Error happens. - static internal void ThrowBluetoothException(int exception) + internal static void ThrowBluetoothException(int exception) + { + throw CreateBluetoothException(exception); + } + + /// + /// Creates Bluetooth Exception. + /// + internal static Exception CreateBluetoothException(int exception) { BluetoothError error = (BluetoothError)exception; switch (error) { - case BluetoothError.InvalidParameter: - throw new InvalidOperationException("Invalid parameter"); + case BluetoothError.InvalidParameter: + return new InvalidOperationException("Invalid parameter"); - case BluetoothError.Cancelled: - throw new InvalidOperationException("Operation cancelled"); + case BluetoothError.Cancelled: + return new InvalidOperationException("Operation cancelled"); - case BluetoothError.AlreadyDone: - throw new InvalidOperationException("Operation already done"); + case BluetoothError.AlreadyDone: + return new InvalidOperationException("Operation already done"); - case BluetoothError.TimedOut: - throw new InvalidOperationException("Timeout error"); + case BluetoothError.TimedOut: + return new InvalidOperationException("Timeout error"); - case BluetoothError.AuthFailed: - throw new InvalidOperationException("Authentication failed"); + case BluetoothError.AuthFailed: + return new InvalidOperationException("Authentication failed"); - case BluetoothError.AuthRejected: - throw new InvalidOperationException("Authentication rejected"); + case BluetoothError.AuthRejected: + return new InvalidOperationException("Authentication rejected"); - case BluetoothError.NoData: - throw new InvalidOperationException("No data available"); + case BluetoothError.NoData: + return new InvalidOperationException("No data available"); - case BluetoothError.NotEnabled: - throw new InvalidOperationException("Local adapter not enabled"); + case BluetoothError.NotEnabled: + return new InvalidOperationException("Local adapter not enabled"); - case BluetoothError.NotInitialized: - throw new InvalidOperationException("Local adapter not initialized"); + case BluetoothError.NotInitialized: + return new InvalidOperationException("Local adapter not initialized"); - case BluetoothError.NowInProgress: - throw new InvalidOperationException("Operation now in progress"); + case BluetoothError.NowInProgress: + return new InvalidOperationException("Operation now in progress"); - case BluetoothError.NotInProgress: - throw new InvalidOperationException("Operation not in progress"); + case BluetoothError.NotInProgress: + return new InvalidOperationException("Operation not in progress"); - case BluetoothError.NotSupported: - throw new NotSupportedException("Bluetooth is not supported"); + case BluetoothError.NotSupported: + return new NotSupportedException("Bluetooth is not supported"); - case BluetoothError.OperationFailed: - throw new InvalidOperationException("Operation failed"); + case BluetoothError.OperationFailed: + return new InvalidOperationException("Operation failed"); - case BluetoothError.OutOfMemory: - throw new InvalidOperationException("Out of memory"); + case BluetoothError.OutOfMemory: + return new InvalidOperationException("Out of memory"); - case BluetoothError.PermissionDenied: - throw new InvalidOperationException("Permission denied"); + case BluetoothError.PermissionDenied: + return new InvalidOperationException("Permission denied"); - case BluetoothError.QuotaExceeded: - throw new InvalidOperationException("Quota exceeded"); + case BluetoothError.QuotaExceeded: + return new InvalidOperationException("Quota exceeded"); - case BluetoothError.RemoteDeviceNotBonded: - throw new InvalidOperationException("Remote device not bonded"); + case BluetoothError.RemoteDeviceNotBonded: + return new InvalidOperationException("Remote device not bonded"); - case BluetoothError.RemoteDeviceNotConnected: - throw new InvalidOperationException("Remote device not connected"); + case BluetoothError.RemoteDeviceNotConnected: + return new InvalidOperationException("Remote device not connected"); - case BluetoothError.RemoteDeviceNotFound: - throw new InvalidOperationException("Remote device not found"); + case BluetoothError.RemoteDeviceNotFound: + return new InvalidOperationException("Remote device not found"); - case BluetoothError.ResourceBusy: - throw new InvalidOperationException("Device or resource busy"); + case BluetoothError.ResourceBusy: + return new InvalidOperationException("Device or resource busy"); - case BluetoothError.ResourceUnavailable: - throw new InvalidOperationException("Resource temporarily unavailable"); + case BluetoothError.ResourceUnavailable: + return new InvalidOperationException("Resource temporarily unavailable"); - case BluetoothError.ServiceNotFound: - throw new InvalidOperationException("Service Not Found"); + case BluetoothError.ServiceNotFound: + return new InvalidOperationException("Service Not Found"); - case BluetoothError.ServiceSearchFailed: - throw new InvalidOperationException("Service search failed"); + case BluetoothError.ServiceSearchFailed: + return new InvalidOperationException("Service search failed"); - default: - throw new InvalidOperationException("Unknown exception"); + default: + return new InvalidOperationException("Unknown exception"); } } } diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEventArgs.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEventArgs.cs index ed9f8f5..d3288e8 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEventArgs.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEventArgs.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; namespace Tizen.Network.Bluetooth { @@ -683,6 +684,76 @@ namespace Tizen.Network.Bluetooth } /// + /// An extended EventArgs class contains the connection state and the address of the remote Bluetooth device. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class HidDeviceConnectionStateChangedEventArgs : EventArgs + { + internal HidDeviceConnectionStateChangedEventArgs(bool isConnected, string address) + { + IsConnected = isConnected; + Address = address; + } + + internal HidDeviceConnectionStateChangedEventArgs(int result, bool isConnected, string address) + { + Result = result; + IsConnected = isConnected; + Address = address; + } + + internal int Result + { + get; + private set; + } + + /// + /// A value indicating whether this instance is connected. + /// + /// 6 + public bool IsConnected + { + get; + private set; + } + + /// + /// The address. + /// + /// 6 + public string Address + { + get; + private set; + } + } + + /// + /// An extended EventArgs class contains the connection state and the address of the remote Bluetooth device. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class HidDeviceDataReceivedEventArgs : EventArgs + { + internal HidDeviceDataReceivedEventArgs(BluetoothHidDeviceReceivedData receivedData) + { + ReceivedData = receivedData; + } + + /// + /// The result. + /// + /// 6 + public BluetoothHidDeviceReceivedData ReceivedData + { + get; + private set; + } + } + + /// /// An extended EventArgs class contains the changed equalizer state. /// /// 3 diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDevice.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDevice.cs new file mode 100644 index 0000000..5d57dd8 --- /dev/null +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDevice.cs @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Threading.Tasks; +using System.ComponentModel; + +namespace Tizen.Network.Bluetooth +{ + /// + /// A class which is used to provide the HID Device role. + /// + /// + /// In HID profile, there are two roles Host and Device. + /// The Host(BluetoothHid) is a device that uses or requests the service of a HID. + /// The Device(BluetoothHidDevice) is a device that provides the service of human data input/output to/from the host. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public class BluetoothHidDevice : BluetoothProfile + { + private TaskCompletionSource _taskForConnection; + private TaskCompletionSource _taskForDisconnection; + + internal BluetoothHidDevice() + { + BluetoothHidDeviceImpl.Instance.ConnectionStateChanged += (s, e) => + { + if (e.Address == RemoteAddress) + { + if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted) + { + if (e.Result == (int)BluetoothError.None) + { + _taskForConnection.SetResult(true); + } + else + { + _taskForConnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result)); + } + } + + if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted) + { + if (e.Result == (int)BluetoothError.None) + { + _taskForDisconnection.SetResult(true); + } + else + { + _taskForDisconnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result)); + } + } + + if (e.Result == (int)BluetoothError.None) + { + /* User does not need 'Result' in HidDeviceConnectionStateChangedEventArgs */ + ConnectionStateChanged?.Invoke(this, new HidDeviceConnectionStateChangedEventArgs(e.IsConnected, e.Address)); + } + } + }; + + BluetoothHidDeviceImpl.Instance.DataReceived += (s, e) => + { + if (e.ReceivedData.Address == RemoteAddress) + { + DataReceived?.Invoke(this, e); + } + }; + } + + /// + /// The ConnectionStateChanged event is called when the HID device connection state is changed. + /// + /// 6 + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler ConnectionStateChanged; + + /// + /// Connects to the remote device asynchronously. + /// + /// 6 + /// A task indicating whether the method is done or not. + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// http://tizen.org/privilege/bluetooth + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public Task ConnectAsync() + { + if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted) + { + BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress); + } + _taskForConnection = new TaskCompletionSource(); + + int ret = BluetoothHidDeviceImpl.Instance.ConnectHidDevice(RemoteAddress); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to connect to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + return _taskForConnection.Task; + } + + /// + /// Disconnects to the remote device asynchronously. + /// + /// 6 + /// A task indicating whether the method is done or not. + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// http://tizen.org/privilege/bluetooth + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public Task DisconnectAsync() + { + if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted) + { + BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress); + } + _taskForDisconnection = new TaskCompletionSource(); + + int ret = BluetoothHidDeviceImpl.Instance.DisconnectHidDevice(RemoteAddress); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to disconnect to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + return _taskForDisconnection.Task; + } + + /// + /// Sends the mouse event data to the remote device. + /// + /// 6 + /// The mouse data to be passed to the remote device. + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// http://tizen.org/privilege/bluetooth + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SendMouseEvent(BluetoothHidMouseData mouseData) + { + BluetoothHidDeviceImpl.Instance.SendHidDeviceMouseEvent(RemoteAddress, mouseData); + } + + /// + /// Sends the key event data to the remote device. + /// + /// 6 + /// The key data to be passed to the remote device. + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// http://tizen.org/privilege/bluetooth + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SendKeyEvent(BluetoothHidKeyData keyData) + { + BluetoothHidDeviceImpl.Instance.SendHidDeviceKeyEvent(RemoteAddress, keyData); + } + + /// + /// The DataReceived event is called when the device receives data from the HID Host. + /// + /// 6 + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler DataReceived; + + /// + /// Replies to reports from the HID Host. + /// + /// 6 + /// The header type to be there in response. + /// The Parameter type to be there in response. + /// Data to be present in data payload of response. + /// http://tizen.org/feature/network.bluetooth + /// http://tizen.org/feature/network.bluetooth.hid_device + /// http://tizen.org/privilege/bluetooth + /// Thrown when the method is failed with message. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ReplyToReport(BluetoothHidHeaderType headerType, BluetoothHidParamType paramType, byte[] data) + { + BluetoothHidDeviceImpl.Instance.ReplyToReportHidDevice(RemoteAddress, headerType, paramType, data); + } + } +} + diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDeviceImpl.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDeviceImpl.cs new file mode 100644 index 0000000..7c05471 --- /dev/null +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothHidDeviceImpl.cs @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Threading.Tasks; + +namespace Tizen.Network.Bluetooth +{ + internal class BluetoothHidDeviceImpl + { + private event EventHandler _hidDeviceConnectionStateChanged; + private event EventHandler _hidDeviceDataReceived; + + private static readonly BluetoothHidDeviceImpl _instance = new BluetoothHidDeviceImpl(); + + internal event EventHandler ConnectionStateChanged + { + add + { + _hidDeviceConnectionStateChanged += value; + } + remove + { + _hidDeviceConnectionStateChanged -= value; + } + } + + internal int ConnectHidDevice(string deviceAddress) + { + return Interop.Bluetooth.ConnectHidDevice(deviceAddress); + } + + internal int DisconnectHidDevice(string deviceAddress) + { + return Interop.Bluetooth.DisconnectHidDevice(deviceAddress); + } + + internal void SendHidDeviceMouseEvent(string deviceAddress, BluetoothHidMouseData mouseData) + { + int ret = Interop.Bluetooth.SendHidDeviceMouseEvent(deviceAddress, mouseData); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to send mouse event to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + + internal void SendHidDeviceKeyEvent(string deviceAddress, BluetoothHidKeyData keyData) + { + int ret = Interop.Bluetooth.SendHidDeviceKeyEvent(deviceAddress, keyData); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to send key event to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + + internal event EventHandler DataReceived + { + add + { + if (_hidDeviceDataReceived == null) + { + RegisterHidDataReceivedEvent(); + } + _hidDeviceDataReceived += value; + } + remove + { + _hidDeviceDataReceived -= value; + if (_hidDeviceDataReceived == null) + { + UnregisterHidDataReceivedEvent(); + } + } + } + + private void RegisterHidDataReceivedEvent() + { + Interop.Bluetooth.HidDeviceDataReceivedCallback _hidDeviceDataReceivedCallback = (ref BluetoothHidDeviceReceivedDataStruct receivedData, IntPtr userData) => + { + _hidDeviceDataReceived?.Invoke(null, new HidDeviceDataReceivedEventArgs(BluetoothHidDeviceReceivedData.Create(receivedData))); + }; + + int ret = Interop.Bluetooth.SetHidDeviceDataReceivedCallback(_hidDeviceDataReceivedCallback, IntPtr.Zero); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to set data received callback, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + + private void UnregisterHidDataReceivedEvent() + { + int ret = Interop.Bluetooth.UnsetHidDeviceDataReceivedCallback(); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to unset data received callback, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + + internal void ReplyToReportHidDevice(string deviceAddress, BluetoothHidHeaderType headerType, BluetoothHidParamType paramType, byte[] data) + { + int ret = Interop.Bluetooth.ReplyToReportHidDevice(deviceAddress, headerType, paramType, data, data.Length, IntPtr.Zero); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to reply to report from hid host, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + + internal static BluetoothHidDeviceImpl Instance + { + get + { + return _instance; + } + } + + private BluetoothHidDeviceImpl() + { + Initialize(); + } + + ~BluetoothHidDeviceImpl() + { + Deinitialize(); + } + + private void Initialize() + { + if (Globals.IsInitialize) + { + Interop.Bluetooth.HidDeviceConnectionStateChangedCallback _hidDeviceConnectionStateChangedCallback = (int result, bool isConnected, string address, IntPtr userData) => + { + _hidDeviceConnectionStateChanged?.Invoke(null, new HidDeviceConnectionStateChangedEventArgs(result, isConnected, address)); + }; + + int ret = Interop.Bluetooth.ActivateHidDevice(_hidDeviceConnectionStateChangedCallback, IntPtr.Zero); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to activate to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + else + { + Log.Error(Globals.LogTag, "Failed to initialize HID Device, BT not initialized"); + BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotInitialized); + } + } + + private void Deinitialize() + { + int ret = Interop.Bluetooth.DeactivateHidDevice(); + if (ret != (int)BluetoothError.None) + { + Log.Error(Globals.LogTag, "Failed to deactivate to the remote device, Error - " + (BluetoothError)ret); + BluetoothErrorFactory.ThrowBluetoothException(ret); + } + } + } +} + diff --git a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothStructs.cs b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothStructs.cs index 44475aa..55cb1d1 100644 --- a/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothStructs.cs +++ b/src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothStructs.cs @@ -205,6 +205,17 @@ namespace Tizen.Network.Bluetooth internal int ServiceDataLength; } + [StructLayout(LayoutKind.Sequential)] + internal struct BluetoothHidDeviceReceivedDataStruct + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + internal string RemoteAddress; + internal BluetoothHidHeaderType headerType; + internal BluetoothHidParamType paramType; + internal int dataSize; + internal IntPtr data; + } + internal static class BluetoothUtils { internal static BluetoothDevice ConvertStructToDeviceClass(BluetoothDeviceStruct device) -- 2.7.4