Change preference error value to match with capi
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Preference / Tizen.Applications / Preference.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 Tizen.Internals.Errors;
20
21 namespace Tizen.Applications
22 {
23     /// <summary>
24     /// The Preference class provides APIs to store and retrieve application specific data/preference. A preference is saved in the form of a key-value pair.
25     /// Keys are always text strings and value can be any one of four types: integer, double, string and boolean.
26     /// </summary>
27     public static class Preference
28     {
29         private const string LogTag = "Tizen.Applications";
30         private static Interop.Preference.ChangedCallback s_preferenceChangedCallback;
31         private static IDictionary<string, EventContext> s_eventMap = new Dictionary<string, EventContext>();
32
33         static Preference()
34         {
35             s_preferenceChangedCallback = (string key, IntPtr userData) =>
36             {
37                 try
38                 {
39                     s_eventMap[key]?.FireEvent();
40                 }
41                 catch (Exception e)
42                 {
43                     Log.Warn(LogTag, e.Message);
44                 }
45             };
46         }
47
48         /// <summary>
49         /// Retrieves all keys of the application preferences
50         /// </summary>
51         /// <value>
52         /// The list of keys
53         /// </value>
54         /// <example>
55         /// <code>
56         ///     Preference.Set("Option_enabled", true);
57         ///     Preference.Set("active_user", "Joe");
58         ///     Preference.Set("default_volume", 10);
59         ///     Preference.Set("brightness", "0.6");
60         ///     foreach(string key in Preference.Keys)
61         ///     {
62         ///         Console.WriteLine("key {0}", key);
63         ///     }
64         /// </code>
65         /// </example>
66         public static IEnumerable<string> Keys
67         {
68             get
69             {
70                 var collection = new List<string>();
71                 Interop.Preference.ItemCallback itemsCallback = (string key, IntPtr userData) =>
72                 {
73                     collection.Add(key);
74                     return true;
75                 };
76                 Interop.Preference.ForeachItem(itemsCallback, IntPtr.Zero);
77                 return collection;
78             }
79         }
80
81         /// <summary>
82         /// Gets the event context for the given key.
83         /// </summary>
84         /// <seealso cref="EventContext"/>
85         /// <param name="key">The preference key</param>
86         /// <returns>The event context of respective key</returns>
87         /// <exception cref="KeyNotFoundException">Thrown if the key is not found</exception>
88         /// <exception cref="ArgumentException">Thrown if the key is an invalid parameter.</exception>
89         /// <example>
90         /// <code>
91         ///     private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e)
92         ///     {
93         ///         Console.WriteLine("key {0}", e.Key);
94         ///     }
95         ///
96         ///     Preference.EventContext context = null;
97         ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
98         ///     if(context != null)
99         ///     {
100         ///         context.Changed += Preference_PreferenceChanged;
101         ///     }
102         ///
103         ///     Preference.Set("active_user", "Poe");
104         ///
105         ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
106         ///     if (context != null)
107         ///     {
108         ///         context.Changed -= Preference_PreferenceChanged;
109         ///     }
110         /// </code>
111         /// </example>
112         public static WeakReference<EventContext> GetEventContext(string key)
113         {
114             if (!s_eventMap.ContainsKey(key))
115             {
116                 if (Contains(key))
117                 {
118                     s_eventMap[key] = new EventContext(key);
119                 }
120                 else
121                 {
122                     throw PreferenceErrorFactory.GetException((int)ErrorCode.KeyNotAvailable);
123                 }
124             }
125
126             return new WeakReference<EventContext>(s_eventMap[key]);
127         }
128
129         /// <summary>
130         /// Checks whether the given key exists in the preference.
131         /// </summary>
132         /// <param name="key">The name of the key to check</param>
133         /// <returns>true if the key exists in the preference, otherwise false</returns>
134         /// <exception cref="ArgumentException">Thrown if the key is an invalid parameter.</exception>
135         /// <exception cref="IOException">Thrown when method failed due to internal IO error.</exception>
136         /// <example>
137         /// <code>
138         ///     Preference.Set("active_user", "Joe");
139         ///     bool exists = Preference.Contains("active_user");
140         ///     if (exists)
141         ///     {
142         ///         string value = Preference.Get<string>("active_user");
143         ///         Console.WriteLine("user {0}", value);
144         ///     }
145         /// </code>
146         /// </example>
147         public static bool Contains(string key)
148         {
149             bool contains;
150             int ret = Interop.Preference.IsExisting(key, out contains);
151             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
152             {
153                 Log.Error(LogTag, "Failed to find key");
154                 throw PreferenceErrorFactory.GetException(ret);
155             }
156
157             return contains;
158         }
159
160         /// <summary>
161         /// Sets a key-value pair representing the preference.
162         /// </summary>
163         /// <remarks>
164         /// If the key already exists in the Preference, old value will be overwritten with new value.
165         /// Data types supported for value are: integer, double, string and bool.
166         /// </remarks>
167         /// <param name="key">The name of the key to create/modigy</param>
168         /// <param name="value">The value corresponding to the key.</param>
169         /// <exception cref="ArgumentException">Thrown if the key is an invalid parameter.</exception>
170         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
171         /// <example>
172         /// <code>
173         ///     Preference.Set("Option_enabled", true);
174         ///     Preference.Set("active_user", "Joe");
175         ///     Preference.Set("default_volume", 10);
176         ///     Preference.Set("brightness", "0.6");
177         /// </code>
178         /// </example>
179         public static void Set(string key, object value)
180         {
181             int ret = 0;
182             if (value is int)
183             {
184                 ret = Interop.Preference.SetInt(key, (int)value);
185                 if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
186                 {
187                     Log.Error(LogTag, "Failed to find key");
188                     throw PreferenceErrorFactory.GetException(ret);
189                 }
190             }
191             else if (value is double)
192             {
193                 ret = Interop.Preference.SetDouble(key, (double)value);
194                 if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
195                 {
196                     Log.Error(LogTag, "Failed to find key");
197                     throw PreferenceErrorFactory.GetException(ret);
198                 }
199             }
200             else if (value is string)
201             {
202                 ret = Interop.Preference.SetString(key, (string)value);
203                 if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
204                 {
205                     Log.Error(LogTag, "Failed to find key");
206                     throw PreferenceErrorFactory.GetException(ret);
207                 }
208             }
209             else if (value is bool)
210             {
211                 ret = Interop.Preference.SetBoolean(key, (bool)value);
212                 if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
213                 {
214                     Log.Error(LogTag, "Failed to find key");
215                     throw PreferenceErrorFactory.GetException(ret);
216                 }
217             }
218         }
219
220         /// <summary>
221         /// Gets the value of a preference item with the specified key.
222         /// Note that this is a generic method.
223         /// </summary>
224         /// <typeparam name="T">The generic type to return.</typeparam>
225         /// <param name="key">The key of the preference</param>
226         /// <returns>The value of the preference item if it is of the specified generic type.</returns>
227         /// <exception cref="KeyNotFoundException">Thrown if the key is not found</exception>
228         /// <exception cref="ArgumentException">Thrown if the key is an invalid parameter.</exception>
229         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
230         /// <example>
231         /// <code>
232         ///     bool exists = Preference.Contains("active_user");
233         ///     if (exists)
234         ///     {
235         ///         string value = Preference.Get<string>("active_user");
236         ///         Console.WriteLine("user {0}", value);
237         ///     }
238         /// </code>
239         /// </example>
240         public static T Get<T>(string key)
241         {
242             object result = null;
243             int ret = (int)PreferenceErrorFactory.PreferenceError.None;
244             if (typeof(T) == typeof(bool))
245             {
246                 bool val;
247                 ret = Interop.Preference.GetBoolean(key, out val);
248                 result = val;
249             }
250             else if (typeof(T) == typeof(int))
251             {
252                 int val;
253                 ret = Interop.Preference.GetInt(key, out val);
254                 result = val;
255             }
256             else if (typeof(T) == typeof(string))
257             {
258                 string val;
259                 ret = Interop.Preference.GetString(key, out val);
260                 result = val;
261             }
262             else if (typeof(T) == typeof(double))
263             {
264                 double val;
265                 ret = Interop.Preference.GetDouble(key, out val);
266                 result = val;
267             }
268             else
269             {
270                 Log.Error(LogTag, "Failed to remove key");
271                 throw new ArgumentException("Invalid parameter");
272             }
273
274             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
275             {
276                 Log.Error(LogTag, "Failed to remove key");
277                 throw PreferenceErrorFactory.GetException(ret);
278             }
279
280             return (result != null) ? (T)result : default(T);
281         }
282
283         /// <summary>
284         /// Removes any preference value with the given key.
285         /// </summary>
286         /// <param name="key">The key to remove</param>
287         /// <exception cref="KeyNotFoundException">Thrown if the key is not found</exception>
288         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
289         /// <example>
290         /// <code>
291         ///     bool exists = Preference.Contains("active_user");
292         ///     if (exists)
293         ///     {
294         ///         string value = Preference.Remove("active_user");
295         ///     }
296         /// </code>
297         /// </example>
298         public static void Remove(string key)
299         {
300             int ret = Interop.Preference.Remove(key);
301             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
302             {
303                 Log.Error(LogTag, "Failed to remove key");
304                 throw PreferenceErrorFactory.GetException(ret);
305             }
306         }
307
308         /// <summary>
309         /// Removes all key-value pairs from the preference.
310         /// </summary>
311         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
312         /// <example>
313         /// <code>
314         ///     Preference.Set("Option_enabled", true);
315         ///     Preference.Set("active_user", "Joe");
316         ///     Preference.Set("default_volume", 10);
317         ///     Preference.Set("brightness", "0.6");
318         ///     Preference.RemoveAll();
319         /// </code>
320         /// </example>
321         public static void RemoveAll()
322         {
323             int ret = Interop.Preference.RemoveAll();
324             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
325             {
326                 Log.Error(LogTag, "Failed to remove all keys");
327                 throw PreferenceErrorFactory.GetException(ret);
328             }
329         }
330
331         private static void AllowChangeNotifications(string key)
332         {
333             int ret = Interop.Preference.SetChangedCb(key, s_preferenceChangedCallback, IntPtr.Zero);
334             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
335             {
336                 Log.Error(LogTag, "Failed to set key notification");
337                 throw PreferenceErrorFactory.GetException(ret);
338             }
339         }
340
341         private static void DisallowChangeNotifications(string key)
342         {
343             int ret = Interop.Preference.UnsetChangedCb(key);
344             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
345             {
346                 Log.Error(LogTag, "Failed to remove key notification");
347                 throw PreferenceErrorFactory.GetException(ret);
348             }
349         }
350
351         /// <summary>
352         /// The class manages event handlers of preference keys. The class enables having event handlers for individual preference keys.
353         /// </summary>
354         public class EventContext
355         {
356             private string _key;
357
358             internal EventContext(string key)
359             {
360                 _key = key;
361             }
362
363             /// <summary>
364             /// Occurs whenever there is change in the value of preference key.
365             /// </summary>
366             /// <exception cref="System.ArgumentException">Thrown when the key does not exist or when there is an invalid parameter.</exception>
367             /// <exception cref="System.InvalidOperationException">Thrown when the Bundle instance has been disposed.</exception>
368             /// <example>
369             /// <code>
370             ///     private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e)
371             ///     {
372             ///         Console.WriteLine("key {0}", e.Key);
373             ///     }
374             ///     Preference.EventContext context = null;
375             ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
376             ///     if(context != null)
377             ///     {
378             ///         context.Changed += Preference_PreferenceChanged;
379             ///     }
380             ///
381             ///     Preference.Set("active_user", "Poe");
382             ///
383             ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
384             ///     if (context != null)
385             ///     {
386             ///         context.Changed -= Preference_PreferenceChanged;
387             ///     }
388             /// </code>
389             /// </example>
390             public event EventHandler<PreferenceChangedEventArgs> Changed
391             {
392                 add
393                 {
394                     if (_changed == null)
395                     {
396                         AllowChangeNotifications(_key);
397                     }
398
399                     _changed += value;
400                 }
401
402                 remove
403                 {
404                     _changed -= value;
405                     if (_changed == null)
406                     {
407                         DisallowChangeNotifications(_key);
408                         s_eventMap.Remove(_key);
409                     }
410                 }
411             }
412
413             private event EventHandler<PreferenceChangedEventArgs> _changed;
414
415             internal void FireEvent()
416             {
417                 _changed?.Invoke(null, new PreferenceChangedEventArgs() { Key = _key });
418             }
419         }
420
421     }
422
423     internal static class PreferenceErrorFactory
424     {
425         internal enum PreferenceError
426         {
427             None = ErrorCode.None,
428             OutOfMemory = ErrorCode.OutOfMemory,
429             InvalidParameter = ErrorCode.InvalidParameter,
430             KeyNotAvailable = -0x01100000 | 0x30,
431             IoError = ErrorCode.IoError
432         }
433
434         static internal Exception GetException(int error)
435         {
436             if ((PreferenceError)error == PreferenceError.OutOfMemory)
437             {
438                 return new OutOfMemoryException("Out of memory");
439             }
440             else if ((PreferenceError)error == PreferenceError.InvalidParameter)
441             {
442                 return new ArgumentException("Invalid parameter");
443             }
444             else if ((PreferenceError)error == PreferenceError.KeyNotAvailable)
445             {
446                 return new KeyNotFoundException("Key does not exist in the bundle");
447             }
448             else if ((PreferenceError)error == PreferenceError.IoError)
449             {
450                 return new System.IO.IOException("I/O Error");
451             }
452             else
453             {
454                 return new ArgumentException("Unknown error");
455             }
456         }
457     }
458 }