/* * 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.Collections.Generic; using System.Runtime.InteropServices; using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Collections.Specialized; namespace Tizen.Network.Bluetooth { /// /// This class is used to handle the connection with other devices and set authorization of other devices.
/// The BluetoothDevice class is used to search for services available on remote devices. ///
/// http://tizen.org/privilege/bluetooth public class BluetoothDevice { private event EventHandler _bondCreated; private event EventHandler _bondDestroyed; private event EventHandler _authorizationChanged; private event EventHandler _serviceSearched; private event EventHandler _connectionChanged; private Interop.Bluetooth.BondCreatedCallback _bondCreatedCallback; private Interop.Bluetooth.BondDestroyedCallback _bondDestroyedCallback; private Interop.Bluetooth.AuthorizationChangedCallback _authorizationChangedCallback; private Interop.Bluetooth.ServiceSearchedCallback _serviceSearchedCallback; private Interop.Bluetooth.DeviceConnectionStateChangedCallback _connectionChangedCallback; internal string RemoteDeviceAddress; internal string RemoteDeviceName; internal int RemoteDeviceRssi; internal BluetoothClass RemoteDeviceClass; internal Collection RemoteDeviceService; internal int RemoteDeviceCount; internal bool RemotePaired; internal bool RemoteAuthorized; internal bool RemoteConnected; internal BluetoothAppearanceType RemoteAppearance; internal int RemoteManufLength; internal string RemoteManufData; internal BluetoothDevice() { } /// /// The address of the device. /// public string Address { get { return RemoteDeviceAddress; } } /// /// The name of the device. /// public string Name { get { return RemoteDeviceName; } } /// /// The strength indicator of received signal of the device. /// public int Rssi { get { return RemoteDeviceRssi; } } /// /// The class of the device. /// public BluetoothClass Class { get { return RemoteDeviceClass; } } /// /// The service UUID list of the device. /// public IEnumerable ServiceUuidList { get { return RemoteDeviceService; } } /// /// The number of services. /// public int ServiceCount { get { return RemoteDeviceCount; } } /// /// The paired state of the device. /// public bool IsPaired { get { return RemotePaired; } } /// /// The connection state of the device. /// public bool IsConnected { get { return RemoteConnected; } } /// /// The authorization state of the device. /// public bool IsAuthorized { get { return RemoteAuthorized; } } /// /// The Bluetooth appearance. /// public BluetoothAppearanceType AppearanceType { get { return RemoteAppearance; } } /// /// The length of the manufacturer data. /// public int ManufacturerDataLength { get { return RemoteManufLength; } } /// /// The manufacturer data. /// public string ManufacturerData { get { return RemoteManufData; } } /// /// The BondCreated event is raised when the process of creating the bond is finished. /// public event EventHandler BondCreated { add { if (_bondCreated == null) { RegisterBondCreatedEvent(); } _bondCreated += value; } remove { _bondCreated -= value; if (_bondCreated == null) { UnregisterBondCreatedEvent(); } } } /// /// The BondDestroyed event is raised when the bond is destroyed. /// public event EventHandler BondDestroyed { add { if (_bondDestroyed == null) { RegisterBondDestroyedEvent(); } _bondDestroyed += value; } remove { _bondDestroyed -= value; if (_bondDestroyed == null) { UnregisterBondDestroyedEvent(); } } } /// /// The AuthorizationChanged event is raised when the authorization of the device is changed. /// public event EventHandler AuthorizationChanged { add { if (_authorizationChanged == null) { RegisterAuthorizationChangedEvent(); } _authorizationChanged += value; } remove { _authorizationChanged -= value; if (_authorizationChanged == null) { UnregisterAuthorizationChangedEvent(); } } } /// /// The ServiceSearched event is raised when the process of service searched is finished. /// public event EventHandler ServiceSearched { add { if (_serviceSearched == null) { RegisterServiceSearchedEvent(); } _serviceSearched += value; } remove { _serviceSearched -= value; if (_serviceSearched == null) { UnregisterServiceSearchedEvent(); } } } /// /// The ConnectionStateChanged event is raised when the connection state is changed. /// public event EventHandler ConnectionStateChanged { add { if (_connectionChanged == null) { RegisterConnectionChangedEvent(); } _connectionChanged += value; } remove { _connectionChanged -= value; if (_connectionChanged == null) { UnregisterConnectionChangedEvent(); } } } private void RegisterBondCreatedEvent() { _bondCreatedCallback = (int result, ref BluetoothDeviceStruct device, IntPtr userData) => { if (_bondCreated != null) { BluetoothError res = (BluetoothError)result; _bondCreated(null, new BondCreatedEventArgs(res, BluetoothUtils.ConvertStructToDeviceClass(device))); } }; int ret = Interop.Bluetooth.SetBondCreatedCallback(_bondCreatedCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set bond created callback, Error - " + (BluetoothError)ret); } } private void UnregisterBondCreatedEvent() { int ret = Interop.Bluetooth.UnsetBondCreatedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset bond created callback, Error - " + (BluetoothError)ret); } } private void RegisterBondDestroyedEvent() { _bondDestroyedCallback = (int result, string deviceAddress, IntPtr userData) => { if (_bondDestroyed != null) { BluetoothError res = (BluetoothError)result; _bondDestroyed(null, new BondDestroyedEventArgs(res, deviceAddress)); } }; int ret = Interop.Bluetooth.SetBondDestroyedCallback(_bondDestroyedCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set bond destroyed callback, Error - " + (BluetoothError)ret); } } private void UnregisterBondDestroyedEvent() { int ret = Interop.Bluetooth.UnsetBondDestroyedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset bond destroyed callback, Error - " + (BluetoothError)ret); } } private void RegisterServiceSearchedEvent() { _serviceSearchedCallback = (int result, ref BluetoothDeviceSdpStruct sdp, IntPtr userData) => { Log.Info(Globals.LogTag, "Servicesearched cb is called"); if (_serviceSearched != null) { BluetoothError res = (BluetoothError)result; _serviceSearched(null, new ServiceSearchedEventArgs(res, BluetoothUtils.ConvertStructToSdpData(sdp))); } }; int ret = Interop.Bluetooth.SetServiceSearchedCallback(_serviceSearchedCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set service searched callback, Error - " + (BluetoothError)ret); } } private void UnregisterServiceSearchedEvent() { int ret = Interop.Bluetooth.UnsetServiceSearchedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset service searched callback, Error - " + (BluetoothError)ret); } } private void RegisterAuthorizationChangedEvent() { _authorizationChangedCallback = (int authorization, string deviceAddress, IntPtr userData) => { Log.Info(Globals.LogTag, "Authorization changed cb is called"); if (_authorizationChanged != null) { BluetoothAuthorizationType auth = (BluetoothAuthorizationType)authorization; _authorizationChanged(null, new AuthorizationChangedEventArgs(auth, deviceAddress)); } }; int ret = Interop.Bluetooth.SetAuthorizationChangedCallback(_authorizationChangedCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set authroization changed callback, Error - " + (BluetoothError)ret); } } private void UnregisterAuthorizationChangedEvent() { int ret = Interop.Bluetooth.UnsetAuthorizationChangedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset authroization changed callback, Error - " + (BluetoothError)ret); } } private void RegisterConnectionChangedEvent() { _connectionChangedCallback = (bool connected, ref BluetoothDeviceConnectionStruct device, IntPtr userData) => { Log.Info(Globals.LogTag, "Connection state changed cb is called"); if (_connectionChanged != null) { _connectionChanged(null, new DeviceConnectionStateChangedEventArgs(connected, BluetoothUtils.ConvertStructToConnectionData(device))); } }; int ret = Interop.Bluetooth.SetConnectionStateChangedCallback(_connectionChangedCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set connection state changed callback, Error - " + (BluetoothError)ret); } } private void UnregisterConnectionChangedEvent() { int ret = Interop.Bluetooth.UnsetConnectionStateChangedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset connection state changed callback, Error - " + (BluetoothError)ret); } } /// /// Creates a bond with the remote Bluetooth device. /// /// /// The Bluetooth must be enabled and the remote device must be discoverable by StartDiscovery(). The bond can be destroyed by DestroyBond(). /// The bonding request can be cancelled by CancelBonding(). If this succeeds, the BondCreated event will be invoked. /// /// Thrown when the BT/BTLE is not enabled /// or when the create bonding process to the remote device fails. public void CreateBond() { if (BluetoothAdapter.IsBluetoothEnabled) { int ret = Interop.Bluetooth.CreateBond(RemoteDeviceAddress); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to create bond, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } /// /// Cancels the bonding process. /// /// /// Bonding must be in progress by CreateBond(). /// /// Thrown when the BT/BTLE is not enabled /// or when the cancel bonding procedure to remote device fails. public void CancelBonding() { int ret = Interop.Bluetooth.CancelBonding(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to cancel bonding process, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } /// /// Destroys the bond. /// /// /// The Bluetooth must be enabled and the bond must be created by CreateBond(). /// If this succeeds, the BondDestroyed event will be invoked. /// /// Thrown when the BT/BTLE is not enabled /// or when the destroy bonding procedure fails. public void DestroyBond() { if (BluetoothAdapter.IsBluetoothEnabled) { int ret = Interop.Bluetooth.DestroyBond(RemoteDeviceAddress); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to destroy bond, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } /// /// Sets an alias for the bonded device. /// /// /// The Bluetooth must be enabled and the bond must be created by CreateBond(). /// /// The alias name of the remote device. /// Thrown when the BT/BTLE is not enabled /// or when the set alias name to remote device fails. public void SetAlias(string aliasName) { if (BluetoothAdapter.IsBluetoothEnabled) { int ret = Interop.Bluetooth.SetAlias(RemoteDeviceAddress, aliasName); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set alias name, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } /// /// Sets the authorization of a bonded device. /// /// /// The Bluetooth must be enabled and the bond must be created by CreateBond(). /// If this succeeds, the AuthorizationChanged event will be invoked. /// /// The authorization state. /// Thrown when the BT/BTLE is not enabled /// or when the set authorization to remote device fails. public void SetAuthorization(BluetoothAuthorizationType authorizationState) { if (BluetoothAdapter.IsBluetoothEnabled) { int ret = Interop.Bluetooth.SetAuthorization(RemoteDeviceAddress, (int)authorizationState); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set authroization state, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } /// /// Gets the mask from the UUID. /// /// The service mask list converted from the given UUID list. /// The UUID list of the device. /// Thrown when the BT/BTLE is not enabled /// or when the get Mask from UUID fails. public BluetoothServiceClassType GetMaskFromUuid(string[] uuids) { BluetoothServiceClassType serviceMask; int ret = Interop.Bluetooth.GetMaskFromUuid(uuids, uuids.Length, out serviceMask); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to get service mask, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } return serviceMask; } /// /// Starts the search for services supported by the specified device. /// /// /// The Bluetooth must be enabled and remote device must be discoverable by StartDiscovery(). The bond must be created by CreateBond(). /// If this succeeds, the ServiceSearched event will be invoked. /// /// Thrown when the BT/BTLE is not enabled /// or when the remote device service search fails. public void StartServiceSearch() { Log.Info(Globals.LogTag, "startservicesearch entry"); if (BluetoothAdapter.IsBluetoothEnabled) { int ret = Interop.Bluetooth.StartServiceSearch(RemoteDeviceAddress); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to start service search, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } /// /// Gets the connected profiles. /// /// /// The Bluetooth must be enabled. /// /// The connected Bluetooth profiles. /// Thrown when the BT/BTLE is not enabled /// or when there is no BT connection. public IEnumerable GetConnectedProfiles() { if (BluetoothAdapter.IsBluetoothEnabled) { List profileList = new List(); Interop.Bluetooth.ConnectedProfileCallback callback = (int profile, IntPtr userData) => { if (!profile.Equals(null)) { profileList.Add((BluetoothProfileType)profile); } return true; }; int ret = Interop.Bluetooth.GetConnectedProfiles(RemoteDeviceAddress, callback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to get connected profiles, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } return profileList; } else { return null; } } /// /// Determines if profile is connected to the specified remote device. /// /// /// The Bluetooth must be enabled. /// /// true if profile is connected, otherwise false. /// The Bluetooth profile type. /// Thrown when the BT/BTLE is not enabled /// or when there is no BT connection. public bool IsProfileConnected(BluetoothProfileType profileType) { if (BluetoothAdapter.IsBluetoothEnabled) { bool isConnected; int ret = Interop.Bluetooth.IsProfileConnected(RemoteDeviceAddress, (int)profileType, out isConnected); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to get profile connected state, Error - " + (BluetoothError)ret); } return isConnected; } else { return false; } } /// /// Returns the instance of the Bluetooth profile type. /// /// /// The Bluetooth must be enabled. /// 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; } return profile; } /// /// Creates the client socket. /// /// The IBluetoothClientSocket instance. /// The UUID of the service. public IBluetoothClientSocket CreateSocket(string serviceUuid) { BluetoothSocket clientSocket = new BluetoothSocket(); clientSocket.remoteAddress = this.Address; clientSocket.serviceUuid = serviceUuid; return (IBluetoothClientSocket)clientSocket; } } }