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;
24 using System.ComponentModel;
26 namespace Tizen.Network.Bluetooth
29 /// This class is used to handle the connection with other devices and set authorization of other devices.<br/>
30 /// The BluetoothDevice class is used to search for services available on remote devices.
32 /// <privilege> http://tizen.org/privilege/bluetooth </privilege>
33 /// <since_tizen> 3 </since_tizen>
34 public class BluetoothDevice
36 private event EventHandler<BondCreatedEventArgs> _bondCreated;
37 private event EventHandler<BondDestroyedEventArgs> _bondDestroyed;
38 private event EventHandler<AuthorizationChangedEventArgs> _authorizationChanged;
39 private event EventHandler<ServiceSearchedEventArgs> _serviceSearched;
40 private event EventHandler<DeviceConnectionStateChangedEventArgs> _connectionChanged;
42 private Interop.Bluetooth.BondCreatedCallback _bondCreatedCallback;
43 private Interop.Bluetooth.BondDestroyedCallback _bondDestroyedCallback;
44 private Interop.Bluetooth.AuthorizationChangedCallback _authorizationChangedCallback;
45 private Interop.Bluetooth.ServiceSearchedCallback _serviceSearchedCallback;
46 private Interop.Bluetooth.DeviceConnectionStateChangedCallback _connectionChangedCallback;
47 private Interop.Bluetooth.ConnectedProfileCallback _connectedProfileCallback;
49 internal string RemoteDeviceAddress;
50 internal string RemoteDeviceName;
51 internal int RemoteDeviceRssi;
52 internal BluetoothClass RemoteDeviceClass;
53 internal Collection<string> RemoteDeviceService;
54 internal int RemoteDeviceCount;
55 internal bool RemotePaired;
56 internal bool RemoteAuthorized;
57 internal bool RemoteConnected;
58 internal BluetoothAppearanceType RemoteAppearance;
59 internal int RemoteManufLength;
60 internal string RemoteManufData;
62 internal BluetoothDevice()
69 /// <since_tizen> 9 </since_tizen>
70 [EditorBrowsable(EditorBrowsableState.Never)]
71 public BluetoothDevice(BluetoothLeDevice leDevice)
73 RemoteDeviceAddress = leDevice?.RemoteAddress;
77 /// The address of the device.
79 /// <since_tizen> 3 </since_tizen>
84 return RemoteDeviceAddress;
88 /// The name of the device.
90 /// <since_tizen> 3 </since_tizen>
95 return RemoteDeviceName;
99 /// The strength indicator of received signal of the device.
101 /// <since_tizen> 3 </since_tizen>
106 return RemoteDeviceRssi;
110 /// The class of the device.
112 /// <since_tizen> 3 </since_tizen>
113 public BluetoothClass Class
117 return RemoteDeviceClass;
121 /// The service UUID list of the device.
123 /// <since_tizen> 3 </since_tizen>
124 public IEnumerable<string> ServiceUuidList
128 return RemoteDeviceService;
132 /// The number of services.
134 /// <since_tizen> 3 </since_tizen>
135 public int ServiceCount
139 return RemoteDeviceCount;
143 /// The paired state of the device.
145 /// <since_tizen> 3 </since_tizen>
154 /// The connection state of the device.
156 /// <since_tizen> 3 </since_tizen>
157 public bool IsConnected
161 return RemoteConnected;
165 /// The authorization state of the device.
167 /// <since_tizen> 3 </since_tizen>
168 public bool IsAuthorized
172 return RemoteAuthorized;
176 /// The Bluetooth appearance.
178 /// <since_tizen> 3 </since_tizen>
179 public BluetoothAppearanceType AppearanceType
183 return RemoteAppearance;
188 /// The length of the manufacturer data.
190 /// <since_tizen> 3 </since_tizen>
191 public int ManufacturerDataLength
195 return RemoteManufLength;
199 /// The manufacturer data.
201 /// <since_tizen> 3 </since_tizen>
202 public string ManufacturerData
206 return RemoteManufData;
211 /// The BondCreated event is raised when the process of creating the bond is finished.
213 /// <since_tizen> 3 </since_tizen>
214 public event EventHandler<BondCreatedEventArgs> BondCreated
218 if (_bondCreated == null)
220 RegisterBondCreatedEvent();
222 _bondCreated += value;
226 _bondCreated -= value;
227 if (_bondCreated == null)
229 UnregisterBondCreatedEvent();
235 /// The BondDestroyed event is raised when the bond is destroyed.
237 /// <since_tizen> 3 </since_tizen>
238 public event EventHandler<BondDestroyedEventArgs> BondDestroyed
242 if (_bondDestroyed == null)
244 RegisterBondDestroyedEvent();
246 _bondDestroyed += value;
250 _bondDestroyed -= value;
251 if (_bondDestroyed == null)
253 UnregisterBondDestroyedEvent();
259 /// The AuthorizationChanged event is raised when the authorization of the device is changed.
261 /// <since_tizen> 3 </since_tizen>
262 public event EventHandler<AuthorizationChangedEventArgs> AuthorizationChanged
266 if (_authorizationChanged == null)
268 RegisterAuthorizationChangedEvent();
270 _authorizationChanged += value;
274 _authorizationChanged -= value;
275 if (_authorizationChanged == null)
277 UnregisterAuthorizationChangedEvent();
283 /// The ServiceSearched event is raised when the process of service searched is finished.
285 /// <since_tizen> 3 </since_tizen>
286 public event EventHandler<ServiceSearchedEventArgs> ServiceSearched
290 if (_serviceSearched == null)
292 RegisterServiceSearchedEvent();
294 _serviceSearched += value;
298 _serviceSearched -= value;
299 if (_serviceSearched == null)
301 UnregisterServiceSearchedEvent();
307 /// The ConnectionStateChanged event is raised when the connection state is changed.
309 /// <since_tizen> 3 </since_tizen>
310 public event EventHandler<DeviceConnectionStateChangedEventArgs> ConnectionStateChanged
314 if (_connectionChanged == null)
316 RegisterConnectionChangedEvent();
318 _connectionChanged += value;
322 _connectionChanged -= value;
323 if (_connectionChanged == null)
325 UnregisterConnectionChangedEvent();
330 private void RegisterBondCreatedEvent()
332 _bondCreatedCallback = (int result, ref BluetoothDeviceStruct device, IntPtr userData) =>
334 if (_bondCreated != null)
336 BluetoothError res = (BluetoothError)result;
337 _bondCreated(null, new BondCreatedEventArgs(res, BluetoothUtils.ConvertStructToDeviceClass(device)));
340 int ret = Interop.Bluetooth.SetBondCreatedCallback(_bondCreatedCallback, IntPtr.Zero);
341 if (ret != (int)BluetoothError.None)
343 Log.Error(Globals.LogTag, "Failed to set bond created callback, Error - " + (BluetoothError)ret);
347 private void UnregisterBondCreatedEvent()
349 int ret = Interop.Bluetooth.UnsetBondCreatedCallback();
350 if (ret != (int)BluetoothError.None)
352 Log.Error(Globals.LogTag, "Failed to unset bond created callback, Error - " + (BluetoothError)ret);
356 private void RegisterBondDestroyedEvent()
358 _bondDestroyedCallback = (int result, string deviceAddress, IntPtr userData) =>
360 if (_bondDestroyed != null)
362 BluetoothError res = (BluetoothError)result;
363 _bondDestroyed(null, new BondDestroyedEventArgs(res, deviceAddress));
366 int ret = Interop.Bluetooth.SetBondDestroyedCallback(_bondDestroyedCallback, IntPtr.Zero);
367 if (ret != (int)BluetoothError.None)
369 Log.Error(Globals.LogTag, "Failed to set bond destroyed callback, Error - " + (BluetoothError)ret);
373 private void UnregisterBondDestroyedEvent()
375 int ret = Interop.Bluetooth.UnsetBondDestroyedCallback();
376 if (ret != (int)BluetoothError.None)
378 Log.Error(Globals.LogTag, "Failed to unset bond destroyed callback, Error - " + (BluetoothError)ret);
382 private void RegisterServiceSearchedEvent()
384 _serviceSearchedCallback = (int result, ref BluetoothDeviceSdpStruct sdp, IntPtr userData) =>
386 Log.Info(Globals.LogTag, "Servicesearched cb is called");
387 if (_serviceSearched != null)
389 BluetoothError res = (BluetoothError)result;
390 _serviceSearched(null, new ServiceSearchedEventArgs(res, BluetoothUtils.ConvertStructToSdpData(sdp)));
393 int ret = Interop.Bluetooth.SetServiceSearchedCallback(_serviceSearchedCallback, IntPtr.Zero);
394 if (ret != (int)BluetoothError.None)
396 Log.Error(Globals.LogTag, "Failed to set service searched callback, Error - " + (BluetoothError)ret);
400 private void UnregisterServiceSearchedEvent()
402 int ret = Interop.Bluetooth.UnsetServiceSearchedCallback();
403 if (ret != (int)BluetoothError.None)
405 Log.Error(Globals.LogTag, "Failed to unset service searched callback, Error - " + (BluetoothError)ret);
409 private void RegisterAuthorizationChangedEvent()
411 _authorizationChangedCallback = (int authorization, string deviceAddress, IntPtr userData) =>
413 Log.Info(Globals.LogTag, "Authorization changed cb is called");
414 if (_authorizationChanged != null)
416 BluetoothAuthorizationType auth = (BluetoothAuthorizationType)authorization;
417 _authorizationChanged(null, new AuthorizationChangedEventArgs(auth, deviceAddress));
420 int ret = Interop.Bluetooth.SetAuthorizationChangedCallback(_authorizationChangedCallback, IntPtr.Zero);
421 if (ret != (int)BluetoothError.None)
423 Log.Error(Globals.LogTag, "Failed to set authroization changed callback, Error - " + (BluetoothError)ret);
427 private void UnregisterAuthorizationChangedEvent()
429 int ret = Interop.Bluetooth.UnsetAuthorizationChangedCallback();
430 if (ret != (int)BluetoothError.None)
432 Log.Error(Globals.LogTag, "Failed to unset authroization changed callback, Error - " + (BluetoothError)ret);
436 private void RegisterConnectionChangedEvent()
438 _connectionChangedCallback = (bool connected, ref BluetoothDeviceConnectionStruct device, IntPtr userData) =>
440 Log.Info(Globals.LogTag, "Connection state changed cb is called");
441 if (_connectionChanged != null)
443 _connectionChanged(null, new DeviceConnectionStateChangedEventArgs(connected, BluetoothUtils.ConvertStructToConnectionData(device)));
447 int ret = Interop.Bluetooth.SetConnectionStateChangedCallback(_connectionChangedCallback, IntPtr.Zero);
448 if (ret != (int)BluetoothError.None)
450 Log.Error(Globals.LogTag, "Failed to set connection state changed callback, Error - " + (BluetoothError)ret);
454 private void UnregisterConnectionChangedEvent()
456 int ret = Interop.Bluetooth.UnsetConnectionStateChangedCallback();
457 if (ret != (int)BluetoothError.None)
459 Log.Error(Globals.LogTag, "Failed to unset connection state changed callback, Error - " + (BluetoothError)ret);
464 /// Creates a bond with the remote Bluetooth device.
467 /// The Bluetooth must be enabled and the remote device must be discoverable by StartDiscovery(). The bond can be destroyed by DestroyBond().
468 /// The bonding request can be cancelled by CancelBonding(). If this succeeds, the BondCreated event will be invoked.
470 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
471 /// or when the create bonding process to the remote device fails.</exception>
472 /// <since_tizen> 3 </since_tizen>
473 public void CreateBond()
475 if (BluetoothAdapter.IsBluetoothEnabled)
477 int ret = Interop.Bluetooth.CreateBond(RemoteDeviceAddress);
478 if (ret != (int)BluetoothError.None)
480 Log.Error(Globals.LogTag, "Failed to create bond, Error - " + (BluetoothError)ret);
481 BluetoothErrorFactory.ThrowBluetoothException(ret);
487 /// Cancels the bonding process.
490 /// Bonding must be in progress by CreateBond().
492 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
493 /// or when the cancel bonding procedure to remote device fails.</exception>
494 /// <since_tizen> 3 </since_tizen>
495 public void CancelBonding()
497 int ret = Interop.Bluetooth.CancelBonding();
498 if (ret != (int)BluetoothError.None)
500 Log.Error(Globals.LogTag, "Failed to cancel bonding process, Error - " + (BluetoothError)ret);
501 BluetoothErrorFactory.ThrowBluetoothException(ret);
506 /// Destroys the bond.
509 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
510 /// If this succeeds, the BondDestroyed event will be invoked.
512 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
513 /// or when the destroy bonding procedure fails.</exception>
514 /// <since_tizen> 3 </since_tizen>
515 public void DestroyBond()
517 if (BluetoothAdapter.IsBluetoothEnabled)
519 int ret = Interop.Bluetooth.DestroyBond(RemoteDeviceAddress);
520 if (ret != (int)BluetoothError.None)
522 Log.Error(Globals.LogTag, "Failed to destroy bond, Error - " + (BluetoothError)ret);
523 BluetoothErrorFactory.ThrowBluetoothException(ret);
529 /// Sets an alias for the bonded device.
532 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
534 /// <param name="aliasName">The alias name of the remote device.</param>
535 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
536 /// or when the set alias name to remote device fails.</exception>
537 /// <since_tizen> 3 </since_tizen>
538 public void SetAlias(string aliasName)
540 if (BluetoothAdapter.IsBluetoothEnabled)
542 int ret = Interop.Bluetooth.SetAlias(RemoteDeviceAddress, aliasName);
543 if (ret != (int)BluetoothError.None)
545 Log.Error(Globals.LogTag, "Failed to set alias name, Error - " + (BluetoothError)ret);
546 BluetoothErrorFactory.ThrowBluetoothException(ret);
552 /// Sets the authorization of a bonded device.
555 /// The Bluetooth must be enabled and the bond must be created by CreateBond().
556 /// If this succeeds, the AuthorizationChanged event will be invoked.
558 /// <param name="authorizationState">The authorization state.</param>
559 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
560 /// or when the set authorization to remote device fails.</exception>
561 /// <since_tizen> 3 </since_tizen>
562 public void SetAuthorization(BluetoothAuthorizationType authorizationState)
564 if (BluetoothAdapter.IsBluetoothEnabled)
566 int ret = Interop.Bluetooth.SetAuthorization(RemoteDeviceAddress, (int)authorizationState);
567 if (ret != (int)BluetoothError.None)
569 Log.Error(Globals.LogTag, "Failed to set authroization state, Error - " + (BluetoothError)ret);
570 BluetoothErrorFactory.ThrowBluetoothException(ret);
576 /// Gets the mask from the UUID.
578 /// <returns>The service mask list converted from the given UUID list.</returns>
579 /// <param name="uuids">The UUID list of the device.</param>
580 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
581 /// or when the get Mask from UUID fails.</exception>
582 /// <since_tizen> 3 </since_tizen>
583 public BluetoothServiceClassType GetMaskFromUuid(string[] uuids)
585 BluetoothServiceClassType serviceMask;
587 int ret = Interop.Bluetooth.GetMaskFromUuid(uuids, uuids.Length, out serviceMask);
588 if (ret != (int)BluetoothError.None)
590 Log.Error(Globals.LogTag, "Failed to get service mask, Error - " + (BluetoothError)ret);
591 BluetoothErrorFactory.ThrowBluetoothException(ret);
597 /// Starts the search for services supported by the specified device.
600 /// The Bluetooth must be enabled and remote device must be discoverable by StartDiscovery(). The bond must be created by CreateBond().
601 /// If this succeeds, the ServiceSearched event will be invoked.
603 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
604 /// or when the remote device service search fails.</exception>
605 /// <since_tizen> 3 </since_tizen>
606 public void StartServiceSearch()
608 Log.Info(Globals.LogTag, "startservicesearch entry");
609 if (BluetoothAdapter.IsBluetoothEnabled)
611 int ret = Interop.Bluetooth.StartServiceSearch(RemoteDeviceAddress);
612 if (ret != (int)BluetoothError.None)
614 Log.Error(Globals.LogTag, "Failed to start service search, Error - " + (BluetoothError)ret);
615 BluetoothErrorFactory.ThrowBluetoothException(ret);
621 /// Gets the connected profiles.
624 /// The Bluetooth must be enabled.
626 /// <returns>The connected Bluetooth profiles.</returns>
627 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
628 /// or when there is no BT connection.</exception>
629 /// <since_tizen> 3 </since_tizen>
630 public IEnumerable<BluetoothProfileType> GetConnectedProfiles()
632 if (BluetoothAdapter.IsBluetoothEnabled)
634 List<BluetoothProfileType> profileList = new List<BluetoothProfileType>();
635 _connectedProfileCallback = (int profile, IntPtr userData) =>
637 if (!profile.Equals(null))
639 profileList.Add((BluetoothProfileType)profile);
643 int ret = Interop.Bluetooth.GetConnectedProfiles(RemoteDeviceAddress, _connectedProfileCallback, IntPtr.Zero);
644 if (ret != (int)BluetoothError.None)
646 Log.Error(Globals.LogTag, "Failed to get connected profiles, Error - " + (BluetoothError)ret);
647 BluetoothErrorFactory.ThrowBluetoothException(ret);
658 /// Determines if profile is connected to the specified remote device.
661 /// The Bluetooth must be enabled.
663 /// <returns><c>true</c> if profile is connected, otherwise <c>false</c>.</returns>
664 /// <param name="profileType">The Bluetooth profile type.</param>
665 /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
666 /// or when there is no BT connection.</exception>
667 /// <since_tizen> 3 </since_tizen>
668 public bool IsProfileConnected(BluetoothProfileType profileType)
670 if (BluetoothAdapter.IsBluetoothEnabled)
673 int ret = Interop.Bluetooth.IsProfileConnected(RemoteDeviceAddress, (int)profileType, out isConnected);
674 if (ret != (int)BluetoothError.None)
676 Log.Error(Globals.LogTag, "Failed to get profile connected state, Error - " + (BluetoothError)ret);
687 /// Returns the instance of the Bluetooth profile type.
690 /// The Bluetooth must be enabled.
692 /// <returns>The profile instance.</returns>
693 /// <since_tizen> 3 </since_tizen>
694 public T GetProfile<T>() where T : BluetoothProfile
698 // TODO : Need to check capability of supporting profiles
699 var profile = (T)Activator.CreateInstance(typeof(T), true);
700 profile.RemoteAddress = RemoteDeviceAddress;
703 catch (TargetInvocationException err)
705 throw err.InnerException;
710 /// Creates the client socket.
712 /// <returns>The IBluetoothClientSocket instance.</returns>
713 /// <param name="serviceUuid">The UUID of the service.</param>
714 /// <since_tizen> 3 </since_tizen>
715 public IBluetoothClientSocket CreateSocket(string serviceUuid)
717 BluetoothSocket clientSocket = new BluetoothSocket();
718 clientSocket.remoteAddress = this.Address;
719 clientSocket.serviceUuid = serviceUuid;
720 return (IBluetoothClientSocket)clientSocket;