/*
* 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
/// 3
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;
private Interop.Bluetooth.ConnectedProfileCallback _connectedProfileCallback;
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.
///
/// 3
public string Address
{
get
{
return RemoteDeviceAddress;
}
}
///
/// The name of the device.
///
/// 3
public string Name
{
get
{
return RemoteDeviceName;
}
}
///
/// The strength indicator of received signal of the device.
///
/// 3
public int Rssi
{
get
{
return RemoteDeviceRssi;
}
}
///
/// The class of the device.
///
/// 3
public BluetoothClass Class
{
get
{
return RemoteDeviceClass;
}
}
///
/// The service UUID list of the device.
///
/// 3
public IEnumerable ServiceUuidList
{
get
{
return RemoteDeviceService;
}
}
///
/// The number of services.
///
/// 3
public int ServiceCount
{
get
{
return RemoteDeviceCount;
}
}
///
/// The paired state of the device.
///
/// 3
public bool IsPaired
{
get
{
return RemotePaired;
}
}
///
/// The connection state of the device.
///
/// 3
public bool IsConnected
{
get
{
return RemoteConnected;
}
}
///
/// The authorization state of the device.
///
/// 3
public bool IsAuthorized
{
get
{
return RemoteAuthorized;
}
}
///
/// The Bluetooth appearance.
///
/// 3
public BluetoothAppearanceType AppearanceType
{
get
{
return RemoteAppearance;
}
}
///
/// The length of the manufacturer data.
///
/// 3
public int ManufacturerDataLength
{
get
{
return RemoteManufLength;
}
}
///
/// The manufacturer data.
///
/// 3
public string ManufacturerData
{
get
{
return RemoteManufData;
}
}
///
/// The BondCreated event is raised when the process of creating the bond is finished.
///
/// 3
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.
///
/// 3
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.
///
/// 3
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.
///
/// 3
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.
///
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
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.
/// 3
public IEnumerable GetConnectedProfiles()
{
if (BluetoothAdapter.IsBluetoothEnabled)
{
List profileList = new List();
_connectedProfileCallback = (int profile, IntPtr userData) =>
{
if (!profile.Equals(null))
{
profileList.Add((BluetoothProfileType)profile);
}
return true;
};
int ret = Interop.Bluetooth.GetConnectedProfiles(RemoteDeviceAddress, _connectedProfileCallback, 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.
/// 3
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.
///
/// The profile instance.
/// 3
public T GetProfile() where T : BluetoothProfile
{
// TODO : Need to check capability of supporting profiles
var profile = (T)Activator.CreateInstance(typeof(T), true);
profile.RemoteAddress = RemoteDeviceAddress;
return profile;
}
///
/// Creates the client socket.
///
/// The IBluetoothClientSocket instance.
/// The UUID of the service.
/// 3
public IBluetoothClientSocket CreateSocket(string serviceUuid)
{
BluetoothSocket clientSocket = new BluetoothSocket();
clientSocket.remoteAddress = this.Address;
clientSocket.serviceUuid = serviceUuid;
return (IBluetoothClientSocket)clientSocket;
}
}
}