Merge remote-tracking branch 'origin/API8' into tizen_6.0
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.WiFi / Tizen.Network.WiFi / WiFiManagerImpl.cs
1 /*
2  * Copyright (c) 2018 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.Threading;
20 using System.Threading.Tasks;
21 using System.Runtime.InteropServices;
22 using Tizen.Applications;
23
24 namespace Tizen.Network.WiFi
25 {
26     static internal class Globals
27     {
28         internal const string LogTag = "Tizen.Network.WiFi";
29     }
30
31     internal class HandleHolder
32     {
33         private SafeWiFiManagerHandle _handle;
34
35         internal HandleHolder()
36         {
37             _handle = WiFiManagerImpl.Instance.Initialize();
38             Log.Info(Globals.LogTag, "Handle: " + _handle);
39         }
40
41         internal SafeWiFiManagerHandle GetSafeHandle()
42         {
43             Log.Debug(Globals.LogTag, "Handleholder safehandle = " + _handle);
44             return _handle;
45         }
46     }
47
48     internal partial class WiFiManagerImpl
49     {
50         private static readonly Lazy<WiFiManagerImpl> _instance =
51             new Lazy<WiFiManagerImpl>(() => new WiFiManagerImpl());
52
53         private TizenSynchronizationContext context = new TizenSynchronizationContext();
54         
55         private Dictionary<IntPtr, Interop.WiFi.VoidCallback> _callback_map =
56             new Dictionary<IntPtr, Interop.WiFi.VoidCallback>();
57         
58         private int _requestId = 0;
59         private string _macAddress;
60
61         //private string PrivilegeNetworkSet = "http://tizen.org/privilege/network.set";
62         private string PrivilegeNetworkGet = "http://tizen.org/privilege/network.get";
63         private string PrivilegeNetworkProfile = "http://tizen.org/privilege/network.get";
64
65         internal string MacAddress
66         {
67             get
68             {
69                 if (String.IsNullOrEmpty(_macAddress))
70                 {
71                     string address;
72                     int ret = Interop.WiFi.GetMacAddress(GetSafeHandle(), out address);
73                     if (ret != (int)WiFiError.None)
74                     {
75                         Log.Error(Globals.LogTag, "Failed to get mac address, Error - " + (WiFiError)ret);
76                         _macAddress = "";
77                     }
78                     else
79                     {
80                         _macAddress = address;
81                     }
82                 }
83                 return _macAddress;
84             }
85         }
86
87         internal string InterfaceName
88         {
89             get
90             {
91                 string name;
92                 int ret = Interop.WiFi.GetNetworkInterfaceName(GetSafeHandle(), out name);
93                 if (ret != (int)WiFiError.None)
94                 {
95                     Log.Error(Globals.LogTag, "Failed to get interface name, Error - " + (WiFiError)ret);
96                     return "";
97                 }
98                 return name;
99             }
100         }
101
102         internal WiFiConnectionState ConnectionState
103         {
104             get
105             {
106                 int state;
107                 int ret = Interop.WiFi.GetConnectionState(GetSafeHandle(), out state);
108                 if (ret != (int)WiFiError.None)
109                 {
110                     Log.Error(Globals.LogTag, "Failed to get connection state, Error - " + (WiFiError)ret);
111                     return WiFiConnectionState.Failure;
112                 }
113                 return (WiFiConnectionState)state;
114             }
115         }
116
117         internal bool IsActive
118         {
119             get
120             {
121                 bool active;
122                 int ret = Interop.WiFi.IsActive(GetSafeHandle(), out active);
123                 if (ret != (int)WiFiError.None)
124                 {
125                     Log.Error(Globals.LogTag, "Failed to get isActive, Error - " + (WiFiError)ret);
126                 }
127                 return active;
128             }
129         }
130
131         internal WiFiScanState ScanState
132         {
133             get
134             {
135                 int state;
136                 int ret = Interop.WiFi.GetScanState(GetSafeHandle(), out state);
137                 if (ret != (int)WiFiError.None)
138                 {
139                     Log.Error(Globals.LogTag, "Failed to get scan state, Error - " + (WiFiError)ret);
140                     return WiFiScanState.NotScanning;
141                 }
142                 return (WiFiScanState)state;
143             }
144         }
145
146         internal static WiFiManagerImpl Instance
147         {
148             get
149             {
150                return _instance.Value;
151             }
152         }
153
154         private static ThreadLocal<HandleHolder> s_threadName = new ThreadLocal<HandleHolder>(() =>
155         {
156             Log.Info(Globals.LogTag, "In threadlocal delegate");
157             return new HandleHolder();
158         });
159
160         private WiFiManagerImpl()
161         {
162             Log.Info(Globals.LogTag, "WiFiManagerImpl constructor");
163         }
164
165         internal SafeWiFiManagerHandle GetSafeHandle()
166         {
167             return s_threadName.Value.GetSafeHandle();
168         }
169
170         internal SafeWiFiManagerHandle Initialize()
171         {
172             SafeWiFiManagerHandle handle;
173             int tid = Thread.CurrentThread.ManagedThreadId;
174             Log.Info(Globals.LogTag, "PInvoke wifi_manager_initialize");
175             int ret = Interop.WiFi.Initialize(tid, out handle);
176             if (ret != (int)WiFiError.None)
177             {
178                 Log.Error(Globals.LogTag, "Initialize Fail, Error - " + (WiFiError)ret);
179                 WiFiErrorFactory.ThrowWiFiException(ret, PrivilegeNetworkGet);
180             }
181             handle.SetTID(tid);
182             return handle;
183         }
184
185         internal IEnumerable<WiFiAP> GetFoundAPs()
186         {
187             Log.Info(Globals.LogTag, "GetFoundAPs");
188             List<WiFiAP> apList = new List<WiFiAP>();
189             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
190             {
191                 if (apHandle != IntPtr.Zero)
192                 {
193                     IntPtr clonedHandle;
194                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
195                     WiFiAP apItem = new WiFiAP(clonedHandle);
196                     apList.Add(apItem);
197                     return true;
198                 }
199                 return false;
200             };
201
202             int ret = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero);
203             CheckReturnValue(ret, "GetForeachFoundAPs", PrivilegeNetworkGet);
204
205             return apList;
206         }
207
208         internal IEnumerable<WiFiAP> GetFoundSpecificAPs()
209         {
210             Log.Info(Globals.LogTag, "GetFoundSpecificAPs");
211             List<WiFiAP> apList = new List<WiFiAP>();
212             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
213             {
214                 if (apHandle != IntPtr.Zero)
215                 {
216                     IntPtr clonedHandle;
217                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
218                     WiFiAP apItem = new WiFiAP(clonedHandle);
219                     apList.Add(apItem);
220                     return true;
221                 }
222                 return false;
223
224             };
225
226             int ret = Interop.WiFi.GetForeachFoundSpecificAPs(GetSafeHandle(), callback, IntPtr.Zero);
227             CheckReturnValue(ret, "GetForeachFoundSpecificAPs", PrivilegeNetworkGet);
228             
229             return apList;
230         }
231
232         internal IEnumerable<WiFiAP> GetFoundBssids()
233         {
234             Log.Info(Globals.LogTag, "GetFoundBssids");
235             List<WiFiAP> apList = new List<WiFiAP>();
236             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
237             {
238                 if (apHandle != IntPtr.Zero)
239                 {
240                     IntPtr clonedHandle;
241                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
242                     WiFiAP apItem = new WiFiAP(clonedHandle);
243                     apList.Add(apItem);
244                     return true;
245                 }
246                 return false;
247             };
248
249             int ret = Interop.WiFi.GetForeachFoundBssids(GetSafeHandle(), callback, IntPtr.Zero);
250             CheckReturnValue(ret, "GetForeachFoundBssids", PrivilegeNetworkGet);
251
252             return apList;
253         }
254
255         internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations()
256         {
257             Log.Debug(Globals.LogTag, "GetWiFiConfigurations");
258             List<WiFiConfiguration> configList = new List<WiFiConfiguration>();
259             Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) =>
260             {
261                 if (configHandle != IntPtr.Zero)
262                 {
263                     IntPtr clonedConfig;
264                     Interop.WiFi.Config.Clone(configHandle, out clonedConfig);
265                     WiFiConfiguration configItem = new WiFiConfiguration(clonedConfig);
266                     configList.Add(configItem);
267                     return true;
268                 }
269                 return false;
270             };
271
272             int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero);
273             CheckReturnValue(ret, "GetForeachConfiguration", PrivilegeNetworkProfile);
274             return configList;
275         }
276
277         internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config)
278         {
279             Log.Debug(Globals.LogTag, "SaveWiFiNetworkConfiguration");
280             if (config == null)
281             {
282                 throw new ArgumentNullException("WiFi configuration is null");
283             }
284
285             IntPtr configHandle = config.GetHandle();
286             int ret = Interop.WiFi.Config.SaveConfiguration(GetSafeHandle(), configHandle);
287             CheckReturnValue(ret, "SaveConfiguration", PrivilegeNetworkProfile);
288        }
289
290         internal WiFiAP GetConnectedAP()
291         {
292             Log.Info(Globals.LogTag, "GetConnectedAP");
293             IntPtr apHandle;
294             int ret = Interop.WiFi.GetConnectedAP(GetSafeHandle(), out apHandle);
295             if (ret == (int)WiFiError.NoConnectionError)
296             {
297                 Log.Error(Globals.LogTag, "No connection " + (WiFiError)ret);
298                 return null;
299             }
300             CheckReturnValue(ret, "GetConnectedAP", PrivilegeNetworkGet);
301             WiFiAP ap = new WiFiAP(apHandle);
302             return ap;
303         }
304
305         internal Task ActivateAsync()
306         {
307             Log.Info(Globals.LogTag, "ActivateAsync");
308             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
309             IntPtr id;
310             lock (_callback_map)
311             {
312                 id = (IntPtr)_requestId++;
313                 _callback_map[id] = (error, key) =>
314                 {
315                     Log.Info(Globals.LogTag, "ActivateAsync done");
316                     if (error != (int)WiFiError.None)
317                     {
318                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
319                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi activating"));
320                     }
321                     else
322                     {
323                         task.SetResult(true);
324                     }
325                     lock (_callback_map)
326                     {
327                         _callback_map.Remove(key);
328                     }
329                 };
330             }
331
332             context.Post((x) =>
333             {
334                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateAsync");
335                 try
336                 {
337                     int ret = Interop.WiFi.Activate(GetSafeHandle(), _callback_map[id], id);
338                     CheckReturnValue(ret, "Activate", "");
339                 }
340                 catch (Exception e)
341                 {
342                     Log.Error(Globals.LogTag, "Exception on ActivateAsync\n" + e);
343                     task.SetException(e);
344                 }
345             }, null);
346
347             return task.Task;
348         }
349
350         internal Task ActivateWithWiFiPickerTestedAsync()
351         {
352             Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync");
353             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
354             IntPtr id;
355             lock (_callback_map)
356             {
357                 id = (IntPtr)_requestId++;
358                 _callback_map[id] = (error, key) =>
359                 {
360                     Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync done");
361                     if (error != (int)WiFiError.None)
362                     {
363                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
364                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi activating"));
365                     }
366                     else
367                     {
368                         task.SetResult(true);
369                     }
370                     lock (_callback_map)
371                     {
372                         _callback_map.Remove(key);
373                     }
374                 };
375             }
376
377             context.Post((x) =>
378             {
379                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateWithWiFiPickerTestedAsync");
380                 try
381                 {
382                     int ret = Interop.WiFi.ActivateWithWiFiPickerTested(GetSafeHandle(), _callback_map[id], id);
383                     CheckReturnValue(ret, "ActivateWithWiFiPickerTested", "");
384                 }
385                 catch (Exception e)
386                 {
387                     Log.Error(Globals.LogTag, "Exception on ActivateWithWiFiPickerTestedAsync\n" + e);
388                     task.SetException(e);
389                 }
390             }, null);
391             
392             return task.Task;
393         }
394
395         internal Task DeactivateAsync()
396         {
397             Log.Info(Globals.LogTag, "DeactivateAsync");
398             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
399             IntPtr id;
400             lock (_callback_map)
401             {
402                 id = (IntPtr)_requestId++;
403                 _callback_map[id] = (error, key) =>
404                 {
405                     Log.Info(Globals.LogTag, "DeactivateAsync done");
406                     if (error != (int)WiFiError.None)
407                     {
408                         Log.Error(Globals.LogTag, "Error occurs during WiFi deactivating, " + (WiFiError)error);
409                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi deactivating"));
410                     }
411                     else
412                     {
413                         task.SetResult(true);
414                     }
415                     lock (_callback_map)
416                     {
417                         _callback_map.Remove(key);
418                     }
419                 };
420             }
421
422             context.Post((x) =>
423             {
424                 Log.Info(Globals.LogTag, "Interop.WiFi.Deactivate");
425                 try
426                 {
427                     int ret = Interop.WiFi.Deactivate(GetSafeHandle(), _callback_map[id], id);
428                     CheckReturnValue(ret, "Deactivate", "");
429                 }
430                 catch (Exception e)
431                 {
432                     Log.Error(Globals.LogTag, "Exception on Deactivate\n" + e);
433                     task.SetException(e);
434                 }
435             }, null);
436
437             return task.Task;           
438         }
439
440         internal Task ScanAsync()
441         {
442             Log.Info(Globals.LogTag, "ScanAsync");
443             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
444             IntPtr id;
445             lock (_callback_map)
446             {
447                 id = (IntPtr)_requestId++;
448                 _callback_map[id] = (error, key) =>
449                 {
450                     Log.Info(Globals.LogTag, "ScanAsync done");
451                     if (error != (int)WiFiError.None)
452                     {
453                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
454                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
455                     }
456                     else
457                     {
458                         task.SetResult(true);
459                     }
460                     lock (_callback_map)
461                     {
462                         _callback_map.Remove(key);
463                     }
464                 };
465             }
466
467             context.Post((x) =>
468             {
469                 Log.Info(Globals.LogTag, "Interop.WiFi.Scan");
470                 try
471                 {
472                     int ret = Interop.WiFi.Scan(GetSafeHandle(), _callback_map[id], id);
473                     CheckReturnValue(ret, "Scan", "");
474                 }
475                 catch (Exception e)
476                 {
477                     Log.Error(Globals.LogTag, "Exception on Scan\n" + e);
478                     task.SetException(e);
479                 }
480             }, null);
481
482             return task.Task;
483         }
484
485         internal Task ScanSpecificAPAsync(string essid)
486         {
487             Log.Info(Globals.LogTag, "ScanSpecificAPAsync " + essid);
488             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
489             IntPtr id;
490             lock (_callback_map)
491             {
492                 id = (IntPtr)_requestId++;
493                 _callback_map[id] = (error, key) =>
494                 {
495                     Log.Info(Globals.LogTag, "ScanSpecificAPAsync Done " + essid);
496                     if (error != (int)WiFiError.None)
497                     {
498                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
499                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
500                     }
501                     else
502                     {
503                         task.SetResult(true);
504                     }
505                     lock (_callback_map)
506                     {
507                         _callback_map.Remove(key);
508                     }
509                 };
510             }
511
512             context.Post((x) =>
513             {
514                 Log.Info(Globals.LogTag, "Interop.WiFi.ScanSpecificAPAsync");
515                 try
516                 {
517                     int ret = Interop.WiFi.ScanSpecificAP(GetSafeHandle(), essid, _callback_map[id], id);
518                     CheckReturnValue(ret, "ScanSpecificAP", "");
519                 }
520                 catch (Exception e)
521                 {
522                     Log.Error(Globals.LogTag, "Exception on ScanSpecificAPAsync\n" + e);
523                     task.SetException(e);
524                 }
525             }, null);
526
527             return task.Task;
528         }
529
530         internal Task BssidScanAsync()
531         {
532             Log.Info(Globals.LogTag, "BssidScanAsync");
533             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
534             IntPtr id;
535             lock (_callback_map)
536             {
537                 id = (IntPtr)_requestId++;
538                 _callback_map[id] = (error, key) =>
539                 {
540                     Log.Info(Globals.LogTag, "BssidScanAsync done");
541                     if (error != (int)WiFiError.None)
542                     {
543                         Log.Error(Globals.LogTag, "Error occurs during bssid scanning, " + (WiFiError)error);
544                         task.SetException(new InvalidOperationException("Error occurs during bssid scanning, " + (WiFiError)error));
545                     }
546                     else
547                     {
548                         task.SetResult(true);
549                     }
550                     lock (_callback_map)
551                     {
552                         _callback_map.Remove(key);
553                     }
554                 };
555             }
556
557             context.Post((x) =>
558             {
559                 Log.Info(Globals.LogTag, "Interop.WiFi.BssidScan");
560                 try
561                 {
562                     int ret = Interop.WiFi.BssidScan(GetSafeHandle(), _callback_map[id], id);
563                     CheckReturnValue(ret, "BssidScan", "");
564                 }
565                 catch (Exception e)
566                 {
567                     Log.Error(Globals.LogTag, "Exception on BssidScan\n" + e);
568                     task.SetException(e);
569                 }
570             }, null);
571
572             return task.Task;
573         }
574
575         private void CheckReturnValue(int ret, string method, string privilege)
576         {
577             if (ret != (int)WiFiError.None)
578             {
579                 Log.Error(Globals.LogTag, method + " Fail, Error - " + (WiFiError)ret);
580                 if (ret == (int)WiFiError.InvalidParameterError)
581                 {
582                     throw new InvalidOperationException("Invalid handle");
583                 }
584                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), privilege);
585             }
586         }
587     }
588 }