2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.Collections.Concurrent;
21 using System.Collections.ObjectModel;
22 using System.Collections.Specialized;
23 using System.Reflection;
25 namespace Tizen.Network.Bluetooth
28 /// This class is used to handle the connection with other devices and set authorization of other devices.<br/>
29 /// The BluetoothDevice class is used to search for services available on remote devices.
31 /// <privilege> http://tizen.org/privilege/bluetooth </privilege>
32 /// <since_tizen> 3 </since_tizen>
33 public class BluetoothDevice
35 private event EventHandler<BondCreatedEventArgs> _bondCreated;
36 private event EventHandler<BondDestroyedEventArgs> _bondDestroyed;
37 private event EventHandler<AuthorizationChangedEventArgs> _authorizationChanged;
38 private event EventHandler<ServiceSearchedEventArgs> _serviceSearched;
39 private event EventHandler<DeviceConnectionStateChangedEventArgs> _connectionChanged;
41 private Interop.Bluetooth.BondCreatedCallback _bondCreatedCallback;
42 private Interop.Bluetooth.BondDestroyedCallback _bondDestroyedCallback;
43 private Interop.Bluetooth.AuthorizationChangedCallback _authorizationChangedCallback;
44 private Interop.Bluetooth.ServiceSearchedCallback _serviceSearchedCallback;
45 private Interop.Bluetooth.DeviceConnectionStateChangedCallback _connectionChangedCallback;
46 private Interop.Bluetooth.ConnectedProfileCallback _connectedProfileCallback;
48 internal string RemoteDeviceAddress;
49 internal string RemoteDeviceName;
50 internal int RemoteDeviceRssi;
51 internal BluetoothClass RemoteDeviceClass;
52 internal Collection<string> RemoteDeviceService;
53 internal int RemoteDeviceCount;
54 internal bool RemotePaired;
55 internal bool RemoteAuthorized;
56 internal bool RemoteConnected;
57 internal BluetoothAppearanceType RemoteAppearance;
58 internal int RemoteManufLength;
59 internal string RemoteManufData;
61 internal BluetoothDevice()
66 /// The address of the device.
68 /// <since_tizen> 3 </since_tizen>
73 return RemoteDeviceAddress;
77 /// The name of the device.
79 /// <since_tizen> 3 </since_tizen>
84 return RemoteDeviceName;
88 /// The strength indicator of received signal of the device.
90 /// <since_tizen> 3 </since_tizen>
95 return RemoteDeviceRssi;
99 /// The class of the device.
101 /// <since_tizen> 3 </since_tizen>
102 public BluetoothClass Class
106 return RemoteDeviceClass;
110 /// The service UUID list of the device.
112 /// <since_tizen> 3 </since_tizen>
113 public IEnumerable<string> ServiceUuidList
117 return RemoteDeviceService;
121 /// The number of services.
123 /// <since_tizen> 3 </since_tizen>
124 public int ServiceCount
128 return RemoteDeviceCount;
132 /// The paired state of the device.
134 /// <since_tizen> 3 </since_tizen>
143 /// The connection state of the device.
145 /// <since_tizen> 3 </since_tizen>
146 public bool IsConnected
150 return RemoteConnected;
154 /// The authorization state of the device.
156 /// <since_tizen> 3 </since_tizen>
157 public bool IsAuthorized
161 return RemoteAuthorized;
165 /// The Bluetooth appearance.
167 /// <since_tizen> 3 </since_tizen>
168 public BluetoothAppearanceType AppearanceType
172 return RemoteAppearance;
177 /// The length of the manufacturer data.
179 /// <since_tizen> 3 </since_tizen>
180 public int ManufacturerDataLength
184 return RemoteManufLength;
188 /// The manufacturer data.
190 /// <since_tizen> 3 </since_tizen>
191 public string ManufacturerData
195 return RemoteManufData;
200 /// The BondCreated event is raised when the process of creating the bond is finished.
202 /// <since_tizen> 3 </since_tizen>
203 public event EventHandler<BondCreatedEventArgs> BondCreated
207 if (_bondCreated == null)
209 RegisterBondCreatedEvent();
211 _bondCreated += value;
215 _bondCreated -= value;
216 if (_bondCreated == null)
218 UnregisterBondCreatedEvent();
224 /// The BondDestroyed event is raised when the bond is destroyed.
226 /// <since_tizen> 3 </since_tizen>
227 public event EventHandler<BondDestroyedEventArgs> BondDestroyed
231 if (_bondDestroyed == null)
233 RegisterBondDestroyedEvent();
235 _bondDestroyed += value;
239 _bondDestroyed -= value;
240 if (_bondDestroyed == null)
242 UnregisterBondDestroyedEvent();
248 /// The AuthorizationChanged event is raised when the authorization of the device is changed.
250 /// <since_tizen> 3 </since_tizen>
251 public event EventHandler<AuthorizationChangedEventArgs> AuthorizationChanged
255 if (_authorizationChanged == null)
257 RegisterAuthorizationChangedEvent();
259 _authorizationChanged += value;
263 _authorizationChanged -= value;
264 if (_authorizationChanged == null)
266 UnregisterAuthorizationChangedEvent();
272 /// The ServiceSearched event is raised when the process of service searched is finished.
274 /// <since_tizen> 3 </since_tizen>
275 public event EventHandler<ServiceSearchedEventArgs> ServiceSearched
279 if (_serviceSearched == null)
281 RegisterServiceSearchedEvent();
283 _serviceSearched += value;
287 _serviceSearched -= value;
288 if (_serviceSearched == null)
290 UnregisterServiceSearchedEvent();
296 /// The ConnectionStateChanged event is raised when the connection state is changed.
298 /// <since_tizen> 3 </since_tizen>
299 public event EventHandler<DeviceConnectionStateChangedEventArgs> ConnectionStateChanged
303 if (_connectionChanged == null)
305 RegisterConnectionChangedEvent();
307 _connectionChanged += value;
311 _connectionChanged -= value;
312 if (_connectionChanged == null)
314 UnregisterConnectionChangedEvent();
319 private void RegisterBondCreatedEvent()
321 _bondCreatedCallback = (int result, ref BluetoothDeviceStruct device, IntPtr userData) =>
323 if (_bondCreated != null)
325 BluetoothError res = (BluetoothError)result;
326 _bondCreated(null, new BondCreatedEventArgs(res, BluetoothUtils.ConvertStructToDeviceClass(device)));
329 int ret = Interop.Bluetooth.SetBondCreatedCallback(_bondCreatedCallback, IntPtr.Zero);
330 if (ret != (int)BluetoothError.None)
332 Log.Error(Globals.LogTag, "Failed to set bond created callback, Error - " + (BluetoothError)ret);
336 private void UnregisterBondCreatedEvent()
338 int ret = Interop.Bluetooth.UnsetBondCreatedCallback();
339 if (ret != (int)BluetoothError.None)
341 Log.Error(Globals.LogTag, "Failed to unset bond created callback, Error - " + (BluetoothError)ret);
345 private void RegisterBondDestroyedEvent()
347 _bondDestroyedCallback = (int result, string deviceAddress, IntPtr userData) =>
349 if (_bondDestroyed != null)
351 BluetoothError res = (BluetoothError)result;
352 _bondDestroyed(null, new BondDestroyedEventArgs(res, deviceAddress));
355 int ret = Interop.Bluetooth.SetBondDestroyedCallback(_bondDestroyedCallback, IntPtr.Zero);
356 if (ret != (int)BluetoothError.None)
358 Log.Error(Globals.LogTag, "Failed to set bond destroyed callback, Error - " + (BluetoothError)ret);
362 private void UnregisterBondDestroyedEvent()
364 int ret = Interop.Bluetooth.UnsetBondDestroyedCallback();
365 if (ret != (int)BluetoothError.None)
367 Log.Error(Globals.LogTag, "Failed to unset bond destroyed callback, Error - " + (BluetoothError)ret);
371 private void RegisterServiceSearchedEvent()
373 _serviceSearchedCallback = (int result, ref BluetoothDeviceSdpStruct sdp, IntPtr userData) =>
375 Log.Info(Globals.LogTag, "Servicesearched cb is called");
376 if (_serviceSearched != null)
378 BluetoothError res = (BluetoothError)result;
379 _serviceSearched(null, new ServiceSearchedEventArgs(res, BluetoothUtils.ConvertStructToSdpData(sdp)));
382 int ret = Interop.Bluetooth.SetServiceSearchedCallback(_serviceSearchedCallback, IntPtr.Zero);
383 if (ret != (int)BluetoothError.None)
385 Log.Error(Globals.LogTag, "Failed to set service searched callback, Error - " + (BluetoothError)ret);
389 private void UnregisterServiceSearchedEvent()
391 int ret = Interop.Bluetooth.UnsetServiceSearchedCallback();
392 if (ret != (int)BluetoothError.None)
394 Log.Error(Globals.LogTag, "Failed to unset service searched callback, Error - " + (BluetoothError)ret);
398 private void RegisterAuthorizationChangedEvent()
400 _authorizationChangedCallback = (int authorization, string deviceAddress, IntPtr userData) =>
402 Log.Info(Globals.LogTag, "Authorization changed cb is called");
403 if (_authorizationChanged != null)
405 BluetoothAuthorizationType auth = (BluetoothAuthorizationType)authorization;
406 _authorizationChanged(null, new AuthorizationChangedEventArgs(auth, deviceAddress));
409 int ret = Interop.Bluetooth.SetAuthorizationChangedCallback(_authorizationChangedCallback, IntPtr.Zero);
410 if (ret != (int)BluetoothError.None)
412 Log.Error(Globals.LogTag, "Failed to set authroization changed callback, Error - " + (BluetoothError)ret);
416 private void UnregisterAuthorizationChangedEvent()
418 int ret = Interop.Bluetooth.UnsetAuthorizationChangedCallback();
419 if (ret != (int)BluetoothError.None)
421 Log.Error(Globals.LogTag, "Failed to unset authroization changed callback, Error - " + (BluetoothError)ret);
425 private void RegisterConnectionChangedEvent()
427 _connectionChangedCallback = (bool connected, ref BluetoothDeviceConnectionStruct device, IntPtr userData) =>
429 Log.Info(Globals.LogTag, "Connection state changed cb is called");
430 if (_connectionChanged != null)
432 _connectionChanged(null, new DeviceConnectionStateChangedEventArgs(connected, BluetoothUtils.ConvertStructToConnectionData(device)));
436 int ret = Interop.Bluetooth.SetConnectionStateChangedCallback(_connectionChangedCallback, IntPtr.Zero);
437 if (ret != (int)BluetoothError.None)
439 Log.Error(Globals.LogTag, "Failed to set connection state changed callback, Error - " + (BluetoothError)ret);
443 private void UnregisterConnectionChangedEvent()
445 int ret = Interop.Bluetooth.UnsetConnectionStateChangedCallback();
446 if (ret != (int)BluetoothError.None)
448 Log.Error(Globals.LogTag, "Failed to unset connection state changed callback, Error - " + (BluetoothError)ret);
453 /// Creates a bond with the remote Bluetooth device.
456 /// The Bluetooth must be enabled and the remote device must be discoverable by StartDiscovery(). The bond can be destroyed by DestroyBond().
457 /// The bonding request can be cancelled by CancelBonding(). If this succeeds, the BondCreated event will be invoked.
459 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
460 /// or when the create bonding process to the remote device fails.</exception>
461 /// <since_tizen> 3 </since_tizen>
462 public void CreateBond()
464 if (BluetoothAdapter.IsBluetoothEnabled)
466 int ret = Interop.Bluetooth.CreateBond(RemoteDeviceAddress);
467 if (ret != (int)BluetoothError.None)
469 Log.Error(Globals.LogTag, "Failed to create bond, Error - " + (BluetoothError)ret);
470 BluetoothErrorFactory.ThrowBluetoothException(ret);
476 /// Cancels the bonding process.
479 /// Bonding must be in progress by CreateBond().
481 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
482 /// or when the cancel bonding procedure to remote device fails.</exception>
483 /// <since_tizen> 3 </since_tizen>
484 public void CancelBonding()
486 int ret = Interop.Bluetooth.CancelBonding();
487 if (ret != (int)BluetoothError.None)
489 Log.Error(Globals.LogTag, "Failed to cancel bonding process, Error - " + (BluetoothError)ret);
490 BluetoothErrorFactory.ThrowBluetoothException(ret);
495 /// Destroys the bond.
498 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
499 /// If this succeeds, the BondDestroyed event will be invoked.
501 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
502 /// or when the destroy bonding procedure fails.</exception>
503 /// <since_tizen> 3 </since_tizen>
504 public void DestroyBond()
506 if (BluetoothAdapter.IsBluetoothEnabled)
508 int ret = Interop.Bluetooth.DestroyBond(RemoteDeviceAddress);
509 if (ret != (int)BluetoothError.None)
511 Log.Error(Globals.LogTag, "Failed to destroy bond, Error - " + (BluetoothError)ret);
512 BluetoothErrorFactory.ThrowBluetoothException(ret);
518 /// Sets an alias for the bonded device.
521 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
523 /// <param name="aliasName">The alias name of the remote device.</param>
524 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
525 /// or when the set alias name to remote device fails.</exception>
526 /// <since_tizen> 3 </since_tizen>
527 public void SetAlias(string aliasName)
529 if (BluetoothAdapter.IsBluetoothEnabled)
531 int ret = Interop.Bluetooth.SetAlias(RemoteDeviceAddress, aliasName);
532 if (ret != (int)BluetoothError.None)
534 Log.Error(Globals.LogTag, "Failed to set alias name, Error - " + (BluetoothError)ret);
535 BluetoothErrorFactory.ThrowBluetoothException(ret);
541 /// Sets the authorization of a bonded device.
544 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
545 /// If this succeeds, the AuthorizationChanged event will be invoked.
547 /// <param name="authorizationState">The authorization state.</param>
548 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
549 /// or when the set authorization to remote device fails.</exception>
550 /// <since_tizen> 3 </since_tizen>
551 public void SetAuthorization(BluetoothAuthorizationType authorizationState)
553 if (BluetoothAdapter.IsBluetoothEnabled)
555 int ret = Interop.Bluetooth.SetAuthorization(RemoteDeviceAddress, (int)authorizationState);
556 if (ret != (int)BluetoothError.None)
558 Log.Error(Globals.LogTag, "Failed to set authroization state, Error - " + (BluetoothError)ret);
559 BluetoothErrorFactory.ThrowBluetoothException(ret);
565 /// Gets the mask from the UUID.
567 /// <returns>The service mask list converted from the given UUID list.</returns>
568 /// <param name="uuids">The UUID list of the device.</param>
569 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
570 /// or when the get Mask from UUID fails.</exception>
571 /// <since_tizen> 3 </since_tizen>
572 public BluetoothServiceClassType GetMaskFromUuid(string[] uuids)
574 BluetoothServiceClassType serviceMask;
576 int ret = Interop.Bluetooth.GetMaskFromUuid(uuids, uuids.Length, out serviceMask);
577 if (ret != (int)BluetoothError.None)
579 Log.Error(Globals.LogTag, "Failed to get service mask, Error - " + (BluetoothError)ret);
580 BluetoothErrorFactory.ThrowBluetoothException(ret);
586 /// Starts the search for services supported by the specified device.
589 /// The Bluetooth must be enabled and remote device must be discoverable by StartDiscovery(). The bond must be created by CreateBond().
590 /// If this succeeds, the ServiceSearched event will be invoked.
592 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
593 /// or when the remote device service search fails.</exception>
594 /// <since_tizen> 3 </since_tizen>
595 public void StartServiceSearch()
597 Log.Info(Globals.LogTag, "startservicesearch entry");
598 if (BluetoothAdapter.IsBluetoothEnabled)
600 int ret = Interop.Bluetooth.StartServiceSearch(RemoteDeviceAddress);
601 if (ret != (int)BluetoothError.None)
603 Log.Error(Globals.LogTag, "Failed to start service search, Error - " + (BluetoothError)ret);
604 BluetoothErrorFactory.ThrowBluetoothException(ret);
610 /// Gets the connected profiles.
613 /// The Bluetooth must be enabled.
615 /// <returns>The connected Bluetooth profiles.</returns>
616 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
617 /// or when there is no BT connection.</exception>
618 /// <since_tizen> 3 </since_tizen>
619 public IEnumerable<BluetoothProfileType> GetConnectedProfiles()
621 if (BluetoothAdapter.IsBluetoothEnabled)
623 List<BluetoothProfileType> profileList = new List<BluetoothProfileType>();
624 _connectedProfileCallback = (int profile, IntPtr userData) =>
626 if (!profile.Equals(null))
628 profileList.Add((BluetoothProfileType)profile);
632 int ret = Interop.Bluetooth.GetConnectedProfiles(RemoteDeviceAddress, _connectedProfileCallback, IntPtr.Zero);
633 if (ret != (int)BluetoothError.None)
635 Log.Error(Globals.LogTag, "Failed to get connected profiles, Error - " + (BluetoothError)ret);
636 BluetoothErrorFactory.ThrowBluetoothException(ret);
647 /// Determines if profile is connected to the specified remote device.
650 /// The Bluetooth must be enabled.
652 /// <returns><c>true</c> if profile is connected, otherwise <c>false</c>.</returns>
653 /// <param name="profileType">The Bluetooth profile type.</param>
654 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
655 /// or when there is no BT connection.</exception>
656 /// <since_tizen> 3 </since_tizen>
657 public bool IsProfileConnected(BluetoothProfileType profileType)
659 if (BluetoothAdapter.IsBluetoothEnabled)
662 int ret = Interop.Bluetooth.IsProfileConnected(RemoteDeviceAddress, (int)profileType, out isConnected);
663 if (ret != (int)BluetoothError.None)
665 Log.Error(Globals.LogTag, "Failed to get profile connected state, Error - " + (BluetoothError)ret);
676 /// Returns the instance of the Bluetooth profile type.
679 /// The Bluetooth must be enabled.
681 /// <returns>The profile instance.</returns>
682 /// <since_tizen> 3 </since_tizen>
683 public T GetProfile<T>() where T : BluetoothProfile
687 // TODO : Need to check capability of supporting profiles
688 var profile = (T)Activator.CreateInstance(typeof(T), true);
689 profile.RemoteAddress = RemoteDeviceAddress;
692 catch (TargetInvocationException err)
694 throw err.InnerException;
699 /// Creates the client socket.
701 /// <returns>The IBluetoothClientSocket instance.</returns>
702 /// <param name="serviceUuid">The UUID of the service.</param>
703 /// <since_tizen> 3 </since_tizen>
704 public IBluetoothClientSocket CreateSocket(string serviceUuid)
706 BluetoothSocket clientSocket = new BluetoothSocket();
707 clientSocket.remoteAddress = this.Address;
708 clientSocket.serviceUuid = serviceUuid;
709 return (IBluetoothClientSocket)clientSocket;