Separate IOException from ArgumentException
[platform/core/csapi/tizenfx.git] / src / Tizen.System.Information / RuntimeInfo / RuntimeInformation.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.IO;
20 using System.Linq;
21 using System.Text;
22 using System.Threading.Tasks;
23 using System.ComponentModel;
24
25 namespace Tizen.System
26 {
27     /// <summary>
28     /// The RuntimeInformation provides functions to obtain runtime information of various system preferences.
29     /// </summary>
30     public static class RuntimeInformation
31     {
32         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_bluetoothEnabled;
33         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_wifiHotspotEnabled;
34         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_bluetoothTetheringEnabled;
35         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_usbTetheringEnabled;
36         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_packetDataEnabled;
37         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_dataRoamingEnabled;
38         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_vibrationEnabled;
39         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_audioJackConnected;
40         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_gpsStatusChanged;
41         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_batteryIsCharging;
42         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_tvOutConnected;
43         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_audioJackConnectorChanged;
44         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_chargerConnected;
45         private static event EventHandler<RuntimeKeyStatusChangedEventArgs> s_autoRotationEnabled;
46
47         private static readonly Interop.RuntimeInfo.RuntimeInformationChangedCallback s_runtimeInfoChangedCallback = (RuntimeInformationKey key, IntPtr userData) =>
48         {
49             RuntimeKeyStatusChangedEventArgs eventArgs = new RuntimeKeyStatusChangedEventArgs()
50             {
51                 Key = key
52             };
53             switch (key)
54             {
55                 case RuntimeInformationKey.Bluetooth:
56                     {
57                         s_bluetoothEnabled?.Invoke(null, eventArgs);
58                         break;
59                     };
60                 case RuntimeInformationKey.WifiHotspot:
61                     {
62                         s_wifiHotspotEnabled?.Invoke(null, eventArgs);
63                         break;
64                     };
65                 case RuntimeInformationKey.BluetoothTethering:
66                     {
67                         s_bluetoothTetheringEnabled?.Invoke(null, eventArgs);
68                         break;
69                     };
70                 case RuntimeInformationKey.UsbTethering:
71                     {
72                         s_usbTetheringEnabled?.Invoke(null, eventArgs);
73                         break;
74                     };
75                 case RuntimeInformationKey.PacketData:
76                     {
77                         s_packetDataEnabled?.Invoke(null, eventArgs);
78                         break;
79                     };
80                 case RuntimeInformationKey.DataRoaming:
81                     {
82                         s_dataRoamingEnabled?.Invoke(null, eventArgs);
83                         break;
84                     };
85                 case RuntimeInformationKey.Vibration:
86                     {
87                         s_vibrationEnabled?.Invoke(null, eventArgs);
88                         break;
89                     };
90                 case RuntimeInformationKey.AudioJack:
91                     {
92                         s_audioJackConnected?.Invoke(null, eventArgs);
93                         break;
94                     };
95                 case RuntimeInformationKey.Gps:
96                     {
97                         s_gpsStatusChanged?.Invoke(null, eventArgs);
98                         break;
99                     };
100                 case RuntimeInformationKey.BatteryIsCharging:
101                     {
102                         s_batteryIsCharging?.Invoke(null, eventArgs);
103                         break;
104                     };
105                 case RuntimeInformationKey.TvOut:
106                     {
107                         s_tvOutConnected?.Invoke(null, eventArgs);
108                         break;
109                     };
110                 case RuntimeInformationKey.AudioJackConnector:
111                     {
112                         s_audioJackConnectorChanged?.Invoke(null, eventArgs);
113                         break;
114                     };
115                 case RuntimeInformationKey.Charger:
116                     {
117                         s_chargerConnected?.Invoke(null, eventArgs);
118                         break;
119                     };
120                 case RuntimeInformationKey.AutoRotation:
121                     {
122                         s_autoRotationEnabled?.Invoke(null, eventArgs);
123                         break;
124                     };
125                 default:
126                     break;
127             };
128         };
129
130         internal static readonly Dictionary<RuntimeInformationKey, Type> s_keyDataTypeMapping = new Dictionary<RuntimeInformationKey, Type>
131         {
132             [RuntimeInformationKey.Bluetooth] = typeof(bool),
133             [RuntimeInformationKey.WifiHotspot] = typeof(bool),
134             [RuntimeInformationKey.BluetoothTethering] = typeof(bool),
135             [RuntimeInformationKey.UsbTethering] = typeof(bool),
136             [RuntimeInformationKey.PacketData] = typeof(bool),
137             [RuntimeInformationKey.DataRoaming] = typeof(bool),
138             [RuntimeInformationKey.Vibration] = typeof(bool),
139             [RuntimeInformationKey.AudioJack] = typeof(bool),
140             [RuntimeInformationKey.BatteryIsCharging] = typeof(bool),
141             [RuntimeInformationKey.TvOut] = typeof(bool),
142             [RuntimeInformationKey.Charger] = typeof(bool),
143             [RuntimeInformationKey.AutoRotation] = typeof(bool),
144             [RuntimeInformationKey.Gps] = typeof(int),
145             [RuntimeInformationKey.AudioJackConnector] = typeof(int)
146         };
147
148         internal static readonly Dictionary<RuntimeInformationKey, int> s_keyTVkeyMapping = new Dictionary<RuntimeInformationKey, int>\r
149         {\r
150             [RuntimeInformationKey.Bluetooth] = 5,
151             [RuntimeInformationKey.WifiHotspot] = 6,
152             [RuntimeInformationKey.BluetoothTethering] = 7,
153             [RuntimeInformationKey.UsbTethering] = 8,
154             [RuntimeInformationKey.PacketData] = 13,
155             [RuntimeInformationKey.DataRoaming] = 14,
156             [RuntimeInformationKey.Vibration] = 16,
157             [RuntimeInformationKey.AudioJack] = 20,
158             [RuntimeInformationKey.BatteryIsCharging] = 22,
159             [RuntimeInformationKey.TvOut] = 18,
160             [RuntimeInformationKey.Charger] = 26,
161             [RuntimeInformationKey.AutoRotation] = 28,
162             [RuntimeInformationKey.Gps] = 21,
163             [RuntimeInformationKey.AudioJackConnector] = 20\r
164         };
165
166         internal static int is_TV_product = -1;
167
168         [EditorBrowsable(EditorBrowsableState.Never)]
169         /// This function is for TV product. It will be removed
170         internal static RuntimeInformationKey ConvertKeyIfTvProduct(RuntimeInformationKey key)\r
171         {\r
172             bool is_key_existed = false;\r
173             string profile;\r
174             int key_TV = -1;
175
176             if (is_TV_product == -1)\r
177             {\r
178                 is_key_existed = SystemInfo.TryGetValue<string>("http://com.samsung/build_config/product_type", out profile);\r
179                 if (is_key_existed && String.Compare(profile, "TV") == 0)\r
180                 {\r
181                     is_TV_product = 1;\r
182                 }\r
183                 else\r
184                 {\r
185                     is_TV_product = 0;\r
186                 }\r
187             }\r
188 \r
189             if (is_TV_product == 0)\r
190             {\r
191                 return key;\r
192             }\r
193             else\r
194             {\r
195                 if (!s_keyTVkeyMapping.TryGetValue(key, out key_TV))\r
196                 {\r
197                     RuntimeInfoErrorFactory.ThrowException((int)RuntimeInfoError.InvalidParameter);\r
198                 }\r
199                 return (RuntimeInformationKey)key_TV;\r
200             }\r
201         }
202
203         [EditorBrowsable(EditorBrowsableState.Never)]
204         internal static object GetStatus(RuntimeInformationKey key)
205         {
206             Type value;
207             if (!s_keyDataTypeMapping.TryGetValue(key, out value))
208             {
209                 RuntimeInfoErrorFactory.ThrowException((int)RuntimeInfoError.InvalidParameter);
210             }
211
212             if (s_keyDataTypeMapping[key] == typeof(int))
213             {
214                 int status;
215                 int ret = Interop.RuntimeInfo.GetValue(ConvertKeyIfTvProduct(key), out status);
216                 if (ret != (int)RuntimeInfoError.None)
217                 {
218                     Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get value for key {0}", key.ToString());
219                     RuntimeInfoErrorFactory.ThrowException(ret);
220                 }
221
222                 return status;
223             }
224             else
225             {
226                 bool status;
227                 int ret = Interop.RuntimeInfo.GetValue(ConvertKeyIfTvProduct(key), out status);
228                 if (ret != (int)RuntimeInfoError.None)
229                 {
230                     Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get value for key {0}", key.ToString());
231                     RuntimeInfoErrorFactory.ThrowException(ret);
232                 }
233
234                 return status;
235             }
236         }
237
238         /// <summary>
239         /// Validates the data type of the status represented by Runtime Key.
240         /// Note that this is a generic method.
241         /// </summary>
242         /// <typeparam name="T">The generic type to validate.</typeparam>
243         /// <param name="key">The runtime information key for which the status type is validated </param>
244         /// <returns>true if the data type matches</returns>.
245         /// <exception cref="ArgumentException">Thrown when the <paramref name="key"/> is invalid.</exception>
246         public static bool Is<T>(RuntimeInformationKey key)
247         {
248             if (!s_keyDataTypeMapping.ContainsKey(key))
249             {
250                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Invalid data type");
251                 throw new ArgumentException("Invalid parameter");
252             }
253
254             return s_keyDataTypeMapping[key] == typeof(T);
255         }
256
257         /// <summary>
258         /// Gets the status of Runtime Key.
259         /// Note that this is a generic method.
260         /// </summary>
261         /// <typeparam name="T">The generic type to return.</typeparam>
262         /// <param name="key">The runtime information key for which the current should be read </param>
263         /// <returns>The current status of the given key</returns>.
264         /// <exception cref="ArgumentException">Thrown when the <paramref name="key"/> is invalid.</exception>
265         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
266         /// <exception cref="NotSupportedException">Thrown when the feature related <paramref name="key"/> is not supported.</exception>
267         public static T GetStatus<T>(RuntimeInformationKey key)
268         {\r
269             return (T)GetStatus(key);
270         }
271
272         /// <summary>
273         /// Gets system memory information
274         /// </summary>
275         /// <returns>The system memory information structure.</returns>
276         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
277         public static SystemMemoryInformation GetSystemMemoryInformation()
278         {
279             Interop.RuntimeInfo.MemoryInfo info = new Interop.RuntimeInfo.MemoryInfo();
280             int ret = Interop.RuntimeInfo.GetSystemMemoryInfo(out info);
281             if (ret != (int)RuntimeInfoError.None)
282             {
283                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get System memory information");
284                 RuntimeInfoErrorFactory.ThrowException(ret);
285             }
286
287             return new SystemMemoryInformation(info);
288         }
289
290         /// <summary>
291         /// Gets memory information per processes
292         /// </summary>
293         /// <param name="pid">List of unique process ids </param>
294         /// <returns>List of memory information per processes</returns>
295         /// <privilege>http://tizen.org/privilege/systemmonitor</privilege>
296         /// <exception cref="ArgumentException">Thrown when the <paramref name="pid"/> is empty.</exception>
297         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system or requesting to resource management daemon.</exception>
298         /// <exception cref="OutOfMemoryException">Thrown when the memory is not enough to allocate.</exception>
299         /// <exception cref="UnauthorizedAccessException">Thrown when caller doesn't have a privilege to use this method.</exception>
300         public static IDictionary<int, ProcessMemoryInformation> GetProcessMemoryInformation(IEnumerable<int> pid)
301         {
302             int[] processArray = pid.ToArray<int>();
303             Interop.RuntimeInfo.ProcessMemoryInfo[] processMemoryArray = new Interop.RuntimeInfo.ProcessMemoryInfo[pid.Count<int>()];
304             Dictionary<int, ProcessMemoryInformation> map = new Dictionary<int, ProcessMemoryInformation>();
305             int ret = Interop.RuntimeInfo.GetProcessMemoryInfo(processArray, pid.Count<int>(), out processMemoryArray);
306             if (ret != (int)RuntimeInfoError.None)
307             {
308                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get Process memory information");
309                 RuntimeInfoErrorFactory.ThrowException(ret);
310             }
311
312             int idx = 0;
313             foreach (Interop.RuntimeInfo.ProcessMemoryInfo cur in processMemoryArray)
314             {
315                 ProcessMemoryInformation processMemory = new ProcessMemoryInformation(cur);
316                 map.Add(processArray[idx], processMemory);
317                 idx++;
318             }
319
320             return map;
321         }
322
323         /// <summary>
324         /// Gets system CPU usage time
325         /// </summary>
326         /// <returns>The system CPU usage time structure.</returns>
327         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
328         public static CpuUsage GetCpuUsage()
329         {
330             Interop.RuntimeInfo.CpuUsage usage = new Interop.RuntimeInfo.CpuUsage();
331             int ret = Interop.RuntimeInfo.GetCpuUsage(out usage);
332             if (ret != (int)RuntimeInfoError.None)
333             {
334                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get cpu usage");
335                 RuntimeInfoErrorFactory.ThrowException(ret);
336             }
337             return new CpuUsage(usage);
338         }
339
340         /// <summary>
341         /// Gets the CPU usage time per process
342         /// </summary>
343         /// <param name="pid">List of unique process ids </param>
344         /// <returns>List of CPU usage information per processes</returns>
345         /// <privilege>http://tizen.org/privilege/systemmonitor</privilege>
346         /// <exception cref="ArgumentException">Thrown when the <paramref name="pid"/> is empty.</exception>
347         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system or requesting to resource management daemon.</exception>
348         /// <exception cref="OutOfMemoryException">Thrown when the memory is not enough to allocate.</exception>
349         /// <exception cref="UnauthorizedAccessException">Thrown when caller doesn't have a privilege to use this method.</exception>
350         public static IDictionary<int, ProcessCpuUsage> GetProcessCpuUsage(IEnumerable<int> pid)
351         {
352             int[] processArray = pid.ToArray<int>();
353             Interop.RuntimeInfo.ProcessCpuUsage[] processCpuUsageArray = new Interop.RuntimeInfo.ProcessCpuUsage[pid.Count<int>()];
354             Dictionary<int, ProcessCpuUsage> map = new Dictionary<int, ProcessCpuUsage>();
355             int ret = Interop.RuntimeInfo.GetProcessCpuUsage(processArray, pid.Count<int>(), out processCpuUsageArray);
356             if (ret != (int)RuntimeInfoError.None)
357             {
358                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get Process cpu usage");
359                 RuntimeInfoErrorFactory.ThrowException(ret);
360             }
361
362             int idx = 0;
363             foreach (Interop.RuntimeInfo.ProcessCpuUsage cur in processCpuUsageArray)
364             {
365                 ProcessCpuUsage processUsage = new ProcessCpuUsage(cur);
366                 map.Add(processArray[idx], processUsage);
367                 idx++;
368             }
369
370             return map;
371         }
372
373         /// <summary>
374         /// Gets the number of processors
375         /// </summary>
376         /// <value>The number of processors</value>
377         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
378         public static int ProcessorCount
379         {
380             get
381             {
382                 int count;
383                 int ret = Interop.RuntimeInfo.GetProcessorCount(out count);
384                 if (ret != (int)RuntimeInfoError.None)
385                 {
386                     Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get Processor count");
387                     RuntimeInfoErrorFactory.ThrowException(ret);
388                 }
389
390                 return count;
391             }
392         }
393
394         /// <summary>
395         /// Gets the current frequency of processor
396         /// </summary>
397         /// <param name="coreId">The index (from 0) of CPU core that you want to know the frequency</param>
398         /// <returns>The current frequency(MHz) of processor</returns>
399         /// <exception cref="ArgumentException">Thrown when the <paramref name="coreid"/> is invalid.</exception>
400         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
401         /// <exception cref="NotSupportedException">Thrown when this system doesn't store CPU current frequency.</exception>
402         public static int GetProcessorCurrentFrequency(int coreId)
403         {
404             int frequency;
405             int ret = Interop.RuntimeInfo.GetProcessorCurrentFrequency(coreId, out frequency);
406             if (ret != (int)RuntimeInfoError.None)
407             {
408                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get Processor current frequency");
409                 RuntimeInfoErrorFactory.ThrowException(ret);
410             }
411             return frequency;
412         }
413
414         /// <summary>
415         /// Gets the max frequency of processor
416         /// </summary>
417         /// <param name="coreId">The index (from 0) of CPU core that you want to know the frequency</param>
418         /// <returns>The max frequency(MHz) of processor</returns>
419         /// <exception cref="ArgumentException">Thrown when the <paramref name="coreid"/> is invalid.</exception>
420         /// <exception cref="IOException">Thrown when I/O error is occurred while reading from system.</exception>
421         /// <exception cref="NotSupportedException">Thrown when this system doesn't store CPU max frequency.</exception>
422         public static int GetProcessorMaxFrequency(int coreId)
423         {
424             int frequency;
425             int ret = Interop.RuntimeInfo.GetProcessorMaxFrequency(coreId, out frequency);
426             if (ret != (int)RuntimeInfoError.None)
427             {
428                 Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to get  Processor max frequency");
429                 RuntimeInfoErrorFactory.ThrowException(ret);
430             }
431             return frequency;
432         }
433
434         /// <summary>
435         /// (event) BluetoothEnabled is raised when system preference for bluetooth is changed.
436         /// </summary>
437         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> BluetoothEnabled
438         {
439             add
440             {
441                 if (s_bluetoothEnabled == null)
442                 {
443                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Bluetooth), s_runtimeInfoChangedCallback, IntPtr.Zero);
444                     if (ret != (int)RuntimeInfoError.None)
445                     {
446                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
447                         RuntimeInfoErrorFactory.ThrowException(ret);
448                     }
449                 }
450                 s_bluetoothEnabled += value;
451             }
452             remove
453             {
454                 s_bluetoothEnabled -= value;
455                 if (s_bluetoothEnabled == null)
456                 {
457                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Bluetooth));
458                     if (ret != (int)RuntimeInfoError.None)
459                     {
460                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
461                         RuntimeInfoErrorFactory.ThrowException(ret);
462                     }
463                 }
464             }
465         }
466         /// <summary>
467         /// (event) WifiHotspotEnabled is raised when system preference for Wi-Fi is changed.
468         /// </summary>
469         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> WifiHotspotEnabled
470         {
471             add
472             {
473                 if (s_wifiHotspotEnabled == null)
474                 {
475                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.WifiHotspot), s_runtimeInfoChangedCallback, IntPtr.Zero);
476                     if (ret != (int)RuntimeInfoError.None)
477                     {
478                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
479                         RuntimeInfoErrorFactory.ThrowException(ret);
480                     }
481                 }
482                 s_wifiHotspotEnabled += value;
483             }
484             remove
485             {
486                 s_wifiHotspotEnabled -= value;
487                 if (s_wifiHotspotEnabled == null)
488                 {
489                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.WifiHotspot));
490                     if (ret != (int)RuntimeInfoError.None)
491                     {
492                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
493                         RuntimeInfoErrorFactory.ThrowException(ret);
494                     }
495                 }
496             }
497         }
498         /// <summary>
499         /// (event) BluetoothTetheringEnabled is raised when system preference for bluetooth tethering is changed.
500         /// </summary>
501         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> BluetoothTetheringEnabled
502         {
503             add
504             {
505                 if (s_bluetoothTetheringEnabled == null)
506                 {
507                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.BluetoothTethering), s_runtimeInfoChangedCallback, IntPtr.Zero);
508                     if (ret != (int)RuntimeInfoError.None)
509                     {
510                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
511                         RuntimeInfoErrorFactory.ThrowException(ret);
512                     }
513                 }
514                 s_bluetoothTetheringEnabled += value;
515             }
516             remove
517             {
518                 s_bluetoothTetheringEnabled -= value;
519                 if (s_bluetoothTetheringEnabled == null)
520                 {
521                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.BluetoothTethering));
522                     if (ret != (int)RuntimeInfoError.None)
523                     {
524                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
525                         RuntimeInfoErrorFactory.ThrowException(ret);
526                     }
527                 }
528             }
529         }
530         /// <summary>
531         /// (event) UsbTetheringEnabled is raised when system preference for USB tethering is changed.
532         /// </summary>
533         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> UsbTetheringEnabled
534         {
535             add
536             {
537                 if (s_usbTetheringEnabled == null)
538                 {
539                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.UsbTethering), s_runtimeInfoChangedCallback, IntPtr.Zero);
540                     if (ret != (int)RuntimeInfoError.None)
541                     {
542                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
543                         RuntimeInfoErrorFactory.ThrowException(ret);
544                     }
545                 }
546                 s_usbTetheringEnabled += value;
547             }
548             remove
549             {
550                 s_usbTetheringEnabled -= value;
551                 if (s_usbTetheringEnabled == null)
552                 {
553                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.UsbTethering));
554                     if (ret != (int)RuntimeInfoError.None)
555                     {
556                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
557                         RuntimeInfoErrorFactory.ThrowException(ret);
558                     }
559                 }
560             }
561         }
562         /// <summary>
563         /// (event) PacketDataEnabled is raised when system preference for package data through 3G network is changed.
564         /// </summary>
565         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> PacketDataEnabled
566         {
567             add
568             {
569                 if (s_packetDataEnabled == null)
570                 {
571                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.PacketData), s_runtimeInfoChangedCallback, IntPtr.Zero);
572                     if (ret != (int)RuntimeInfoError.None)
573                     {
574                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
575                         RuntimeInfoErrorFactory.ThrowException(ret);
576                     }
577                 }
578                 s_packetDataEnabled += value;
579             }
580             remove
581             {
582                 s_packetDataEnabled -= value;
583                 if (s_packetDataEnabled == null)
584                 {
585                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.PacketData));
586                     if (ret != (int)RuntimeInfoError.None)
587                     {
588                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
589                         RuntimeInfoErrorFactory.ThrowException(ret);
590                     }
591                 }
592             }
593         }
594         /// <summary>
595         /// (event) DataRoamingEnabled is raised when system preference for data roaming is changed.
596         /// </summary>
597         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> DataRoamingEnabled
598         {
599             add
600             {
601                 if (s_dataRoamingEnabled == null)
602                 {
603                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.DataRoaming), s_runtimeInfoChangedCallback, IntPtr.Zero);
604                     if (ret != (int)RuntimeInfoError.None)
605                     {
606                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
607                         RuntimeInfoErrorFactory.ThrowException(ret);
608                     }
609                 }
610                 s_dataRoamingEnabled += value;
611             }
612             remove
613             {
614                 s_dataRoamingEnabled -= value;
615                 if (s_dataRoamingEnabled == null)
616                 {
617                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.DataRoaming));
618                     if (ret != (int)RuntimeInfoError.None)
619                     {
620                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
621                         RuntimeInfoErrorFactory.ThrowException(ret);
622                     }
623                 }
624             }
625         }
626         /// <summary>
627         /// (event) VibrationEnabled is raised when system preference for vibration is changed.
628         /// </summary>
629         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> VibrationEnabled
630         {
631             add
632             {
633                 if (s_vibrationEnabled == null)
634                 {
635                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Vibration), s_runtimeInfoChangedCallback, IntPtr.Zero);
636                     if (ret != (int)RuntimeInfoError.None)
637                     {
638                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
639                         RuntimeInfoErrorFactory.ThrowException(ret);
640                     }
641                 }
642                 s_vibrationEnabled += value;
643             }
644             remove
645             {
646                 s_vibrationEnabled -= value;
647                 if (s_vibrationEnabled == null)
648                 {
649                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Vibration));
650                     if (ret != (int)RuntimeInfoError.None)
651                     {
652                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
653                         RuntimeInfoErrorFactory.ThrowException(ret);
654                     }
655                 }
656             }
657         }
658         /// <summary>
659         /// (event) AudioJackConnected is raised when audio jack is connected/disconnected.
660         /// </summary>
661         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> AudioJackConnected
662         {
663             add
664             {
665                 if (s_audioJackConnected == null)
666                 {
667                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AudioJack), s_runtimeInfoChangedCallback, IntPtr.Zero);
668                     if (ret != (int)RuntimeInfoError.None)
669                     {
670                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
671                         RuntimeInfoErrorFactory.ThrowException(ret);
672                     }
673                 }
674                 s_audioJackConnected += value;
675             }
676             remove
677             {
678                 s_audioJackConnected -= value;
679                 if (s_audioJackConnected == null)
680                 {
681                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AudioJack));
682                     if (ret != (int)RuntimeInfoError.None)
683                     {
684                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
685                         RuntimeInfoErrorFactory.ThrowException(ret);
686                     }
687                 }
688             }
689         }
690         /// <summary>
691         /// (event) GpsStatusChanged is raised when status of GPS is changed.
692         /// </summary>
693         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> GpsStatusChanged
694         {
695             add
696             {
697                 if (s_gpsStatusChanged == null)
698                 {
699                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Gps), s_runtimeInfoChangedCallback, IntPtr.Zero);
700                     if (ret != (int)RuntimeInfoError.None)
701                     {
702                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
703                         RuntimeInfoErrorFactory.ThrowException(ret);
704                     }
705                 }
706                 s_gpsStatusChanged += value;
707             }
708             remove
709             {
710                 s_gpsStatusChanged -= value;
711                 if (s_gpsStatusChanged == null)
712                 {
713                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Gps));
714                     if (ret != (int)RuntimeInfoError.None)
715                     {
716                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
717                         RuntimeInfoErrorFactory.ThrowException(ret);
718                     }
719                 }
720             }
721         }
722         /// <summary>
723         /// (event) BatteryIsCharging is raised battery is currently charging.
724         /// </summary>
725         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> BatteryIsCharging
726         {
727             add
728             {
729                 if (s_batteryIsCharging == null)
730                 {
731                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.BatteryIsCharging), s_runtimeInfoChangedCallback, IntPtr.Zero);
732                     if (ret != (int)RuntimeInfoError.None)
733                     {
734                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
735                         RuntimeInfoErrorFactory.ThrowException(ret);
736                     }
737                 }
738                 s_batteryIsCharging += value;
739             }
740             remove
741             {
742                 s_batteryIsCharging -= value;
743                 if (s_batteryIsCharging == null)
744                 {
745                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.BatteryIsCharging));
746                     if (ret != (int)RuntimeInfoError.None)
747                     {
748                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
749                         RuntimeInfoErrorFactory.ThrowException(ret);
750                     }
751                 }
752             }
753         }
754         /// <summary>
755         /// (event) TvOutConnected is raised when TV out is connected/disconnected.
756         /// </summary>
757         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> TvOutConnected
758         {
759             add
760             {
761                 if (s_tvOutConnected == null)
762                 {
763                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.TvOut), s_runtimeInfoChangedCallback, IntPtr.Zero);
764                     if (ret != (int)RuntimeInfoError.None)
765                     {
766                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
767                         RuntimeInfoErrorFactory.ThrowException(ret);
768                     }
769                 }
770                 s_tvOutConnected += value;
771             }
772             remove
773             {
774                 s_tvOutConnected -= value;
775                 if (s_tvOutConnected == null)
776                 {
777                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.TvOut));
778                     if (ret != (int)RuntimeInfoError.None)
779                     {
780                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
781                         RuntimeInfoErrorFactory.ThrowException(ret);
782                     }
783                 }
784             }
785         }
786         /// <summary>
787         /// (event) AudioJackConnectorChanged is raised when audio jack connection changes.
788         /// </summary>
789         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> AudioJackConnectorChanged
790         {
791             add
792             {
793                 if (s_audioJackConnectorChanged == null)
794                 {
795                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AudioJackConnector), s_runtimeInfoChangedCallback, IntPtr.Zero);
796                     if (ret != (int)RuntimeInfoError.None)
797                     {
798                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
799                         RuntimeInfoErrorFactory.ThrowException(ret);
800                     }
801                 }
802                 s_audioJackConnectorChanged += value;
803             }
804             remove
805             {
806                 s_audioJackConnectorChanged -= value;
807                 if (s_audioJackConnectorChanged == null)
808                 {
809                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AudioJackConnector));
810                     if (ret != (int)RuntimeInfoError.None)
811                     {
812                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
813                         RuntimeInfoErrorFactory.ThrowException(ret);
814                     }
815                 }
816             }
817         }
818         /// <summary>
819         /// (event) ChargerConnected is raised when charger is connected/disconnected.
820         /// </summary>
821         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> ChargerConnected
822         {
823             add
824             {
825                 if (s_chargerConnected == null)
826                 {
827                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Charger), s_runtimeInfoChangedCallback, IntPtr.Zero);
828                     if (ret != (int)RuntimeInfoError.None)
829                     {
830                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
831                         RuntimeInfoErrorFactory.ThrowException(ret);
832                     }
833                 }
834                 s_chargerConnected += value;
835             }
836             remove
837             {
838                 s_chargerConnected -= value;
839                 if (s_chargerConnected == null)
840                 {
841                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.Charger));
842                     if (ret != (int)RuntimeInfoError.None)
843                     {
844                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
845                         RuntimeInfoErrorFactory.ThrowException(ret);
846                     }
847                 }
848             }
849         }
850         /// <summary>
851         /// (event) AutoRotationEnabled is raised when system preference for auto rotation is changed.
852         /// </summary>
853         public static event EventHandler<RuntimeKeyStatusChangedEventArgs> AutoRotationEnabled
854         {
855             add
856             {
857                 if (s_autoRotationEnabled == null)
858                 {
859                     int ret = Interop.RuntimeInfo.SetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AutoRotation), s_runtimeInfoChangedCallback, IntPtr.Zero);
860                     if (ret != (int)RuntimeInfoError.None)
861                     {
862                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
863                         RuntimeInfoErrorFactory.ThrowException(ret);
864                     }
865                 }
866                 s_autoRotationEnabled += value;
867             }
868             remove
869             {
870                 s_autoRotationEnabled -= value;
871                 if (s_autoRotationEnabled == null)
872                 {
873                     int ret = Interop.RuntimeInfo.UnsetRuntimeInfoChangedCallback(ConvertKeyIfTvProduct(RuntimeInformationKey.AutoRotation));
874                     if (ret != (int)RuntimeInfoError.None)
875                     {
876                         Log.Error(RuntimeInfoErrorFactory.LogTag, "Interop failed to add event handler");
877                         RuntimeInfoErrorFactory.ThrowException(ret);
878                     }
879                 }
880             }
881         }
882     }
883 }