Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothDevice.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
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
24 namespace Tizen.Network.Bluetooth
25 {
26     /// <summary>
27     /// This class is used to handle the connection with other devices and set authorization of other devices.<br>
28     /// The BluetoothDevice class is used to search for services available on remote devices.
29     /// </summary>
30     /// <privilege> http://tizen.org/privilege/bluetooth </privilege>
31     public class BluetoothDevice
32     {
33         private event EventHandler<BondCreatedEventArgs> _bondCreated;
34         private event EventHandler<BondDestroyedEventArgs> _bondDestroyed;
35         private event EventHandler<AuthorizationChangedEventArgs> _authorizationChanged;
36         private event EventHandler<ServiceSearchedEventArgs> _serviceSearched;
37         private event EventHandler<DeviceConnectionStateChangedEventArgs> _connectionChanged;
38
39         private Interop.Bluetooth.BondCreatedCallback _bondCreatedCallback;
40         private Interop.Bluetooth.BondDestroyedCallback _bondDestroyedCallback;
41         private Interop.Bluetooth.AuthorizationChangedCallback _authorizationChangedCallback;
42         private Interop.Bluetooth.ServiceSearchedCallback _serviceSearchedCallback;
43         private Interop.Bluetooth.DeviceConnectionStateChangedCallback _connectionChangedCallback;
44
45         internal string RemoteDeviceAddress;
46         internal string RemoteDeviceName;
47         internal int RemoteDeviceRssi;
48         internal BluetoothClass RemoteDeviceClass;
49         internal Collection<string> RemoteDeviceService;
50         internal int RemoteDeviceCount;
51         internal bool RemotePaired;
52         internal bool RemoteAuthorized;
53         internal bool RemoteConnected;
54         internal BluetoothAppearanceType RemoteAppearance;
55         internal int RemoteManufLength;
56         internal string RemoteManufData;
57
58         internal BluetoothDevice()
59         {
60         }
61
62         /// <summary>
63         /// The address of the device.
64         /// </summary>
65         public string Address
66         {
67             get
68             {
69                 return RemoteDeviceAddress;
70             }
71         }
72         /// <summary>
73         /// The name of the device.
74         /// </summary>
75         public string Name
76         {
77             get
78             {
79                 return RemoteDeviceName;
80             }
81         }
82         /// <summary>
83         /// The strength indicator of received signal of the device.
84         /// </summary>
85         public int Rssi
86         {
87             get
88             {
89                 return RemoteDeviceRssi;
90             }
91         }
92         /// <summary>
93         /// The class of the device.
94         /// </summary>
95         public BluetoothClass Class
96         {
97             get
98             {
99                 return RemoteDeviceClass;
100             }
101         }
102         /// <summary>
103         /// The service UUID list of the device.
104         /// </summary>
105         public IEnumerable<string> ServiceUuidList
106         {
107             get
108             {
109                 return RemoteDeviceService;
110             }
111         }
112         /// <summary>
113         /// The number of services.
114         /// </summary>
115         public int ServiceCount
116         {
117             get
118             {
119                 return RemoteDeviceCount;
120             }
121         }
122         /// <summary>
123         /// The paired state of the device.
124         /// </summary>
125         public bool IsPaired
126         {
127             get
128             {
129                 return RemotePaired;
130             }
131         }
132         /// <summary>
133         /// The connection state of the device.
134         /// </summary>
135         public bool IsConnected
136         {
137             get
138             {
139                 return RemoteConnected;
140             }
141         }
142         /// <summary>
143         /// The authorization state of the device.
144         /// </summary>
145         public bool IsAuthorized
146         {
147             get
148             {
149                 return RemoteAuthorized;
150             }
151         }
152         /// <summary>
153         /// The Bluetooth appearance.
154         /// </summary>
155         public BluetoothAppearanceType AppearanceType
156         {
157             get
158             {
159                 return RemoteAppearance;
160             }
161         }
162
163         /// <summary>
164         /// The length of the manufacturer data.
165         /// </summary>
166         public int ManufacturerDataLength
167         {
168             get
169             {
170                 return RemoteManufLength;
171             }
172         }
173         /// <summary>
174         /// The manufacturer data.
175         /// </summary>
176         public string ManufacturerData
177         {
178             get
179             {
180                 return RemoteManufData;
181             }
182         }
183
184         /// <summary>
185         /// The BondCreated event is raised when the process of creating the bond is finished.
186         /// </summary>
187         public event EventHandler<BondCreatedEventArgs> BondCreated
188         {
189             add
190             {
191                 if (_bondCreated == null)
192                 {
193                     RegisterBondCreatedEvent();
194                 }
195                 _bondCreated += value;
196             }
197             remove
198             {
199                 _bondCreated -= value;
200                 if (_bondCreated == null)
201                 {
202                     UnregisterBondCreatedEvent();
203                 }
204             }
205         }
206
207         /// <summary>
208         /// The BondDestroyed event is raised when the bond is destroyed.
209         /// </summary>
210         public event EventHandler<BondDestroyedEventArgs> BondDestroyed
211         {
212             add
213             {
214                 if (_bondDestroyed == null)
215                 {
216                     RegisterBondDestroyedEvent();
217                 }
218                 _bondDestroyed += value;
219             }
220             remove
221             {
222                 _bondDestroyed -= value;
223                 if (_bondDestroyed == null)
224                 {
225                     UnregisterBondDestroyedEvent();
226                 }
227             }
228         }
229
230         /// <summary>
231         /// The AuthorizationChanged event is raised when the authorization of the device is changed.
232         /// </summary>
233         public event EventHandler<AuthorizationChangedEventArgs> AuthorizationChanged
234         {
235             add
236             {
237                 if (_authorizationChanged == null)
238                 {
239                     RegisterAuthorizationChangedEvent();
240                 }
241                 _authorizationChanged += value;
242             }
243             remove
244             {
245                 _authorizationChanged -= value;
246                 if (_authorizationChanged == null)
247                 {
248                     UnregisterAuthorizationChangedEvent();
249                 }
250             }
251         }
252
253         /// <summary>
254         /// The ServiceSearched event is raised when the process of service searched is finished.
255         /// </summary>
256         public event EventHandler<ServiceSearchedEventArgs> ServiceSearched
257         {
258             add
259             {
260                 if (_serviceSearched == null)
261                 {
262                     RegisterServiceSearchedEvent();
263                 }
264                 _serviceSearched += value;
265             }
266             remove
267             {
268                 _serviceSearched -= value;
269                 if (_serviceSearched == null)
270                 {
271                     UnregisterServiceSearchedEvent();
272                 }
273             }
274         }
275
276         /// <summary>
277         /// The ConnectionStateChanged event is raised when the connection state is changed.
278         /// </summary>
279         public event EventHandler<DeviceConnectionStateChangedEventArgs> ConnectionStateChanged
280         {
281             add
282             {
283                 if (_connectionChanged == null)
284                 {
285                     RegisterConnectionChangedEvent();
286                 }
287                 _connectionChanged += value;
288             }
289             remove
290             {
291                 _connectionChanged -= value;
292                 if (_connectionChanged == null)
293                 {
294                     UnregisterConnectionChangedEvent();
295                 }
296             }
297         }
298
299         private void RegisterBondCreatedEvent()
300         {
301             _bondCreatedCallback = (int result, ref BluetoothDeviceStruct device, IntPtr userData) =>
302             {
303                 if (_bondCreated != null)
304                 {
305                     BluetoothError res = (BluetoothError)result;
306                     _bondCreated(null, new BondCreatedEventArgs(res, BluetoothUtils.ConvertStructToDeviceClass(device)));
307                 }
308             };
309             int ret = Interop.Bluetooth.SetBondCreatedCallback(_bondCreatedCallback, IntPtr.Zero);
310             if (ret != (int)BluetoothError.None)
311             {
312                 Log.Error(Globals.LogTag, "Failed to set bond created callback, Error - " + (BluetoothError)ret);
313             }
314         }
315
316         private void UnregisterBondCreatedEvent()
317         {
318             int ret = Interop.Bluetooth.UnsetBondCreatedCallback();
319             if (ret != (int)BluetoothError.None)
320             {
321                 Log.Error(Globals.LogTag, "Failed to unset bond created callback, Error - " + (BluetoothError)ret);
322             }
323         }
324
325         private void RegisterBondDestroyedEvent()
326         {
327             _bondDestroyedCallback = (int result, string deviceAddress, IntPtr userData) =>
328             {
329                 if (_bondDestroyed != null)
330                 {
331                     BluetoothError res = (BluetoothError)result;
332                     _bondDestroyed(null, new BondDestroyedEventArgs(res, deviceAddress));
333                 }
334             };
335             int ret = Interop.Bluetooth.SetBondDestroyedCallback(_bondDestroyedCallback, IntPtr.Zero);
336             if (ret != (int)BluetoothError.None)
337             {
338                 Log.Error(Globals.LogTag, "Failed to set bond destroyed callback, Error - " + (BluetoothError)ret);
339             }
340         }
341
342         private void UnregisterBondDestroyedEvent()
343         {
344             int ret = Interop.Bluetooth.UnsetBondDestroyedCallback();
345             if (ret != (int)BluetoothError.None)
346             {
347                 Log.Error(Globals.LogTag, "Failed to unset bond destroyed callback, Error - " + (BluetoothError)ret);
348             }
349         }
350
351         private void RegisterServiceSearchedEvent()
352         {
353             _serviceSearchedCallback = (int result, ref BluetoothDeviceSdpStruct sdp, IntPtr userData) =>
354             {
355                 Log.Info(Globals.LogTag, "Servicesearched cb is called");
356                 if (_serviceSearched != null)
357                 {
358                     BluetoothError res = (BluetoothError)result;
359                     _serviceSearched(null, new ServiceSearchedEventArgs(res, BluetoothUtils.ConvertStructToSdpData(sdp)));
360                 }
361             };
362             int ret = Interop.Bluetooth.SetServiceSearchedCallback(_serviceSearchedCallback, IntPtr.Zero);
363             if (ret != (int)BluetoothError.None)
364             {
365                 Log.Error(Globals.LogTag, "Failed to set service searched callback, Error - " + (BluetoothError)ret);
366             }
367         }
368
369         private void UnregisterServiceSearchedEvent()
370         {
371             int ret = Interop.Bluetooth.UnsetServiceSearchedCallback();
372             if (ret != (int)BluetoothError.None)
373             {
374                 Log.Error(Globals.LogTag, "Failed to unset service searched callback, Error - " + (BluetoothError)ret);
375             }
376         }
377
378         private void RegisterAuthorizationChangedEvent()
379         {
380             _authorizationChangedCallback = (int authorization, string deviceAddress, IntPtr userData) =>
381             {
382                 Log.Info(Globals.LogTag, "Authorization changed cb is called");
383                 if (_authorizationChanged != null)
384                 {
385                     BluetoothAuthorizationType auth = (BluetoothAuthorizationType)authorization;
386                     _authorizationChanged(null, new AuthorizationChangedEventArgs(auth, deviceAddress));
387                 }
388             };
389             int ret = Interop.Bluetooth.SetAuthorizationChangedCallback(_authorizationChangedCallback, IntPtr.Zero);
390             if (ret != (int)BluetoothError.None)
391             {
392                 Log.Error(Globals.LogTag, "Failed to set authroization changed callback, Error - " + (BluetoothError)ret);
393             }
394         }
395
396         private void UnregisterAuthorizationChangedEvent()
397         {
398             int ret = Interop.Bluetooth.UnsetAuthorizationChangedCallback();
399             if (ret != (int)BluetoothError.None)
400             {
401                 Log.Error(Globals.LogTag, "Failed to unset authroization changed callback, Error - " + (BluetoothError)ret);
402             }
403         }
404
405         private void RegisterConnectionChangedEvent()
406         {
407             _connectionChangedCallback = (bool connected, ref BluetoothDeviceConnectionStruct device, IntPtr userData) =>
408             {
409                 Log.Info(Globals.LogTag, "Connection state changed cb is called");
410                 if (_connectionChanged != null)
411                 {
412                     _connectionChanged(null, new DeviceConnectionStateChangedEventArgs(connected, BluetoothUtils.ConvertStructToConnectionData(device)));
413                 }
414             };
415
416             int ret = Interop.Bluetooth.SetConnectionStateChangedCallback(_connectionChangedCallback, IntPtr.Zero);
417             if (ret != (int)BluetoothError.None)
418             {
419                 Log.Error(Globals.LogTag, "Failed to set connection state changed callback, Error - " + (BluetoothError)ret);
420             }
421         }
422
423         private void UnregisterConnectionChangedEvent()
424         {
425             int ret = Interop.Bluetooth.UnsetConnectionStateChangedCallback();
426             if (ret != (int)BluetoothError.None)
427             {
428                 Log.Error(Globals.LogTag, "Failed to unset connection state changed callback, Error - " + (BluetoothError)ret);
429             }
430         }
431
432         /// <summary>
433         /// Creates a bond with the remote Bluetooth device.
434         /// </summary>
435         /// <remarks>
436         /// The Bluetooth must be enabled and the remote device must be discoverable by StartDiscovery(). The bond can be destroyed by DestroyBond().
437         /// The bonding request can be cancelled by CancelBonding(). If this succeeds, the BondCreated event will be invoked.
438         /// </remarks>
439         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
440         /// or when the create bonding process to the remote device fails.</exception>
441         public void CreateBond()
442         {
443             if (BluetoothAdapter.IsBluetoothEnabled)
444             {
445                 int ret = Interop.Bluetooth.CreateBond(RemoteDeviceAddress);
446                 if (ret != (int)BluetoothError.None)
447                 {
448                     Log.Error(Globals.LogTag, "Failed to create bond, Error - " + (BluetoothError)ret);
449                     BluetoothErrorFactory.ThrowBluetoothException(ret);
450                 }
451             }
452         }
453
454         /// <summary>
455         /// Cancels the bonding process.
456         /// </summary>
457         /// <remarks>
458         /// Bonding must be in progress by CreateBond().
459         /// </remarks>
460         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
461         /// or when the cancel bonding procedure to remote device fails.</exception>
462         public void CancelBonding()
463         {
464             int ret = Interop.Bluetooth.CancelBonding();
465             if (ret != (int)BluetoothError.None)
466             {
467                 Log.Error(Globals.LogTag, "Failed to cancel bonding process, Error - " + (BluetoothError)ret);
468                 BluetoothErrorFactory.ThrowBluetoothException(ret);
469             }
470         }
471
472         /// <summary>
473         /// Destroys the bond.
474         /// </summary>
475         /// <remarks>
476         /// The Bluetooth must be enabled and the bond must be created by CreateBond().
477         /// If this succeeds, the BondDestroyed event will be invoked.
478         /// </remarks>
479         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
480         /// or when the destroy bonding procedure fails.</exception>
481         public void DestroyBond()
482         {
483             if (BluetoothAdapter.IsBluetoothEnabled)
484             {
485                 int ret = Interop.Bluetooth.DestroyBond(RemoteDeviceAddress);
486                 if (ret != (int)BluetoothError.None)
487                 {
488                     Log.Error(Globals.LogTag, "Failed to destroy bond, Error - " + (BluetoothError)ret);
489                     BluetoothErrorFactory.ThrowBluetoothException(ret);
490                 }
491             }
492         }
493
494         /// <summary>
495         /// Sets an alias for the bonded device.
496         /// </summary>
497         /// <remarks>
498         /// The Bluetooth must be enabled and the bond must be created by CreateBond().
499         /// </remarks>
500         /// <param name="aliasName">The alias name of the remote device.</param>
501         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
502         /// or when the set alias name to remote device fails.</exception>
503         public void SetAlias(string aliasName)
504         {
505             if (BluetoothAdapter.IsBluetoothEnabled)
506             {
507                 int ret = Interop.Bluetooth.SetAlias(RemoteDeviceAddress, aliasName);
508                 if (ret != (int)BluetoothError.None)
509                 {
510                     Log.Error(Globals.LogTag, "Failed to set alias name, Error - " + (BluetoothError)ret);
511                     BluetoothErrorFactory.ThrowBluetoothException(ret);
512                 }
513             }
514         }
515
516         /// <summary>
517         /// Sets the authorization of a bonded device.
518         /// </summary>
519         /// <remarks>
520         /// The Bluetooth must be enabled and the bond must be created by CreateBond().
521         /// If this succeeds, the AuthorizationChanged event will be invoked.
522         /// </remarks>
523         /// <param name="authorizationState">The authorization state.</param>
524         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
525         /// or when the set authorization to remote device fails.</exception>
526         public void SetAuthorization(BluetoothAuthorizationType authorizationState)
527         {
528             if (BluetoothAdapter.IsBluetoothEnabled)
529             {
530                 int ret = Interop.Bluetooth.SetAuthorization(RemoteDeviceAddress, (int)authorizationState);
531                 if (ret != (int)BluetoothError.None)
532                 {
533                     Log.Error(Globals.LogTag, "Failed to set authroization state, Error - " + (BluetoothError)ret);
534                     BluetoothErrorFactory.ThrowBluetoothException(ret);
535                 }
536             }
537         }
538
539         /// <summary>
540         /// Gets the mask from the UUID.
541         /// </summary>
542         /// <returns>The service mask list converted from the given UUID list.</returns>
543         /// <param name="uuids">The UUID list of the device.</param>
544         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
545         /// or when the get Mask from UUID fails.</exception>
546         public BluetoothServiceClassType GetMaskFromUuid(string[] uuids)
547         {
548             BluetoothServiceClassType serviceMask;
549
550             int ret = Interop.Bluetooth.GetMaskFromUuid(uuids, uuids.Length, out serviceMask);
551             if (ret != (int)BluetoothError.None)
552             {
553                 Log.Error(Globals.LogTag, "Failed to get service mask, Error - " + (BluetoothError)ret);
554                 BluetoothErrorFactory.ThrowBluetoothException(ret);
555             }
556             return serviceMask;
557         }
558
559         /// <summary>
560         /// Starts the search for services supported by the specified device.
561         /// </summary>
562         /// <remarks>
563         /// The Bluetooth must be enabled and remote device must be discoverable by StartDiscovery(). The bond must be created by CreateBond().
564         /// If this succeeds, the ServiceSearched event will be invoked.
565         /// </remarks>
566         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
567         /// or when the remote device service search fails.</exception>
568         public void StartServiceSearch()
569         {
570             Log.Info(Globals.LogTag, "startservicesearch entry");
571             if (BluetoothAdapter.IsBluetoothEnabled)
572             {
573                 int ret = Interop.Bluetooth.StartServiceSearch(RemoteDeviceAddress);
574                 if (ret != (int)BluetoothError.None)
575                 {
576                     Log.Error(Globals.LogTag, "Failed to start service search, Error - " + (BluetoothError)ret);
577                     BluetoothErrorFactory.ThrowBluetoothException(ret);
578                 }
579             }
580         }
581
582         /// <summary>
583         /// Gets the connected profiles.
584         /// </summary>
585         /// <remarks>
586         /// The Bluetooth must be enabled.
587         /// </remarks>
588         /// <returns>The connected Bluetooth profiles.</returns>
589         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
590         /// or when there is no BT connection.</exception>
591         public IEnumerable<BluetoothProfileType> GetConnectedProfiles()
592         {
593             if (BluetoothAdapter.IsBluetoothEnabled)
594             {
595                 List<BluetoothProfileType> profileList = new List<BluetoothProfileType>();
596                 Interop.Bluetooth.ConnectedProfileCallback callback = (int profile, IntPtr userData) =>
597                 {
598                     if (!profile.Equals(null))
599                     {
600                         profileList.Add((BluetoothProfileType)profile);
601                     }
602                     return true;
603                 };
604                 int ret = Interop.Bluetooth.GetConnectedProfiles(RemoteDeviceAddress, callback, IntPtr.Zero);
605                 if (ret != (int)BluetoothError.None)
606                 {
607                     Log.Error(Globals.LogTag, "Failed to get connected profiles, Error - " + (BluetoothError)ret);
608                     BluetoothErrorFactory.ThrowBluetoothException(ret);
609                 }
610                 return profileList;
611             }
612             else
613             {
614                 return null;
615             }
616         }
617
618         /// <summary>
619         /// Determines if profile is connected to the specified remote device.
620         /// </summary>
621         /// <remarks>
622         /// The Bluetooth must be enabled.
623         /// </remarks>
624         /// <returns><c>true</c> if profile is connected, otherwise <c>false</c>.</returns>
625         /// <param name="profileType">The Bluetooth profile type.</param>
626         /// <exception cref="System.InvalidOperationException">Thrown when the BT/BTLE is not enabled
627         /// or when there is no BT connection.</exception>
628         public bool IsProfileConnected(BluetoothProfileType profileType)
629         {
630             if (BluetoothAdapter.IsBluetoothEnabled)
631             {
632                 bool isConnected;
633                 int ret = Interop.Bluetooth.IsProfileConnected(RemoteDeviceAddress, (int)profileType, out isConnected);
634                 if (ret != (int)BluetoothError.None)
635                 {
636                     Log.Error(Globals.LogTag, "Failed to get profile connected state, Error - " + (BluetoothError)ret);
637                 }
638                 return isConnected;
639             }
640             else
641             {
642                 return false;
643             }
644         }
645
646         /// <summary>
647         /// Returns the instance of the Bluetooth profile type.
648         /// </summary>
649         /// <remarks>
650         /// The Bluetooth must be enabled.
651         /// </remarks>
652         public T GetProfile<T>() where T : BluetoothProfile
653         {
654             /*
655              * FIXME: Find a proper way for dynamic allocation.
656              */
657             T profile = null;
658             String type = typeof(T).ToString();
659             if (type.Equals("Tizen.Network.Bluetooth.BluetoothAudio"))
660             {
661                 BluetoothAudio audio = new BluetoothAudio();
662                 profile = (audio as T);
663             }
664             else if (type.Equals("Tizen.Network.Bluetooth.BluetoothAvrcp"))
665             {
666                 BluetoothAvrcp avrcp = new BluetoothAvrcp();
667                 profile = (avrcp as T);
668             }
669             else if (type.Equals("Tizen.Network.Bluetooth.BluetoothHid"))
670             {
671                 BluetoothHid hid = new BluetoothHid();
672                 profile = (hid as T);
673             }
674
675             if (profile != null)
676             {
677                 profile.RemoteAddress = RemoteDeviceAddress;
678             }
679             return profile;
680         }
681
682         /// <summary>
683         /// Creates the client socket.
684         /// </summary>
685         /// <returns>The IBluetoothClientSocket instance.</returns>
686         /// <param name="serviceUuid">The UUID of the service.</param>
687         public IBluetoothClientSocket CreateSocket(string serviceUuid)
688         {
689             BluetoothSocket clientSocket = new BluetoothSocket();
690             clientSocket.remoteAddress = this.Address;
691             clientSocket.serviceUuid = serviceUuid;
692             return (IBluetoothClientSocket)clientSocket;
693         }
694     }
695 }