Release 4.0.0-preview1-00051
[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)PreferenceErrorFactory.PreferenceError.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             else
219             {
220                 Log.Error(LogTag, "Failed to Set");
221                 throw new ArgumentException("Invalid parameter");
222             }
223         }
224
225         /// <summary>
226         /// Gets the value of a preference item with the specified key.
227         /// Note that this is a generic method.
228         /// </summary>
229         /// <typeparam name="T">The generic type to return.</typeparam>
230         /// <param name="key">The key of the preference</param>
231         /// <returns>The value of the preference item if it is of the specified generic type.</returns>
232         /// <exception cref="KeyNotFoundException">Thrown if the key is not found</exception>
233         /// <exception cref="ArgumentException">Thrown if the key is an invalid parameter.</exception>
234         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
235         /// <example>
236         /// <code>
237         ///     bool exists = Preference.Contains("active_user");
238         ///     if (exists)
239         ///     {
240         ///         string value = Preference.Get<string>("active_user");
241         ///         Console.WriteLine("user {0}", value);
242         ///     }
243         /// </code>
244         /// </example>
245         public static T Get<T>(string key)
246         {
247             object result = null;
248             int ret = (int)PreferenceErrorFactory.PreferenceError.None;
249             if (typeof(T) == typeof(bool))
250             {
251                 bool val;
252                 ret = Interop.Preference.GetBoolean(key, out val);
253                 result = val;
254             }
255             else if (typeof(T) == typeof(int))
256             {
257                 int val;
258                 ret = Interop.Preference.GetInt(key, out val);
259                 result = val;
260             }
261             else if (typeof(T) == typeof(string))
262             {
263                 string val;
264                 ret = Interop.Preference.GetString(key, out val);
265                 result = val;
266             }
267             else if (typeof(T) == typeof(double))
268             {
269                 double val;
270                 ret = Interop.Preference.GetDouble(key, out val);
271                 result = val;
272             }
273             else
274             {
275                 Log.Error(LogTag, "Failed to remove key");
276                 throw new ArgumentException("Invalid parameter");
277             }
278
279             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
280             {
281                 Log.Error(LogTag, "Failed to remove key");
282                 throw PreferenceErrorFactory.GetException(ret);
283             }
284
285             return (result != null) ? (T)result : default(T);
286         }
287
288         /// <summary>
289         /// Removes any preference value with the given key.
290         /// </summary>
291         /// <param name="key">The key to remove</param>
292         /// <exception cref="KeyNotFoundException">Thrown if the key is not found</exception>
293         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
294         /// <example>
295         /// <code>
296         ///     bool exists = Preference.Contains("active_user");
297         ///     if (exists)
298         ///     {
299         ///         string value = Preference.Remove("active_user");
300         ///     }
301         /// </code>
302         /// </example>
303         public static void Remove(string key)
304         {
305             int ret = Interop.Preference.Remove(key);
306             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
307             {
308                 Log.Error(LogTag, "Failed to remove key");
309                 throw PreferenceErrorFactory.GetException(ret);
310             }
311         }
312
313         /// <summary>
314         /// Removes all key-value pairs from the preference.
315         /// </summary>
316         /// <exception cref="System.IO.IOException">Thrown when method failed due to internal IO error.</exception>
317         /// <example>
318         /// <code>
319         ///     Preference.Set("Option_enabled", true);
320         ///     Preference.Set("active_user", "Joe");
321         ///     Preference.Set("default_volume", 10);
322         ///     Preference.Set("brightness", "0.6");
323         ///     Preference.RemoveAll();
324         /// </code>
325         /// </example>
326         public static void RemoveAll()
327         {
328             int ret = Interop.Preference.RemoveAll();
329             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
330             {
331                 Log.Error(LogTag, "Failed to remove all keys");
332                 throw PreferenceErrorFactory.GetException(ret);
333             }
334         }
335
336         private static void AllowChangeNotifications(string key)
337         {
338             int ret = Interop.Preference.SetChangedCb(key, s_preferenceChangedCallback, IntPtr.Zero);
339             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
340             {
341                 Log.Error(LogTag, "Failed to set key notification");
342                 throw PreferenceErrorFactory.GetException(ret);
343             }
344         }
345
346         private static void DisallowChangeNotifications(string key)
347         {
348             int ret = Interop.Preference.UnsetChangedCb(key);
349             if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
350             {
351                 Log.Error(LogTag, "Failed to remove key notification");
352                 throw PreferenceErrorFactory.GetException(ret);
353             }
354         }
355
356         /// <summary>
357         /// The class manages event handlers of preference keys. The class enables having event handlers for individual preference keys.
358         /// </summary>
359         public class EventContext
360         {
361             private string _key;
362
363             internal EventContext(string key)
364             {
365                 _key = key;
366             }
367
368             /// <summary>
369             /// Occurs whenever there is change in the value of preference key.
370             /// </summary>
371             /// <exception cref="System.ArgumentException">Thrown when the key does not exist or when there is an invalid parameter.</exception>
372             /// <exception cref="System.InvalidOperationException">Thrown when the Bundle instance has been disposed.</exception>
373             /// <example>
374             /// <code>
375             ///     private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e)
376             ///     {
377             ///         Console.WriteLine("key {0}", e.Key);
378             ///     }
379             ///     Preference.EventContext context = null;
380             ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
381             ///     if(context != null)
382             ///     {
383             ///         context.Changed += Preference_PreferenceChanged;
384             ///     }
385             ///
386             ///     Preference.Set("active_user", "Poe");
387             ///
388             ///     Preference.GetEventContext("active_user").TryGetTarget(out context);
389             ///     if (context != null)
390             ///     {
391             ///         context.Changed -= Preference_PreferenceChanged;
392             ///     }
393             /// </code>
394             /// </example>
395             public event EventHandler<PreferenceChangedEventArgs> Changed
396             {
397                 add
398                 {
399                     if (_changed == null)
400                     {
401                         AllowChangeNotifications(_key);
402                     }
403
404                     _changed += value;
405                 }
406
407                 remove
408                 {
409                     _changed -= value;
410                     if (_changed == null)
411                     {
412                         DisallowChangeNotifications(_key);
413                         s_eventMap.Remove(_key);
414                     }
415                 }
416             }
417
418             private event EventHandler<PreferenceChangedEventArgs> _changed;
419
420             internal void FireEvent()
421             {
422                 _changed?.Invoke(null, new PreferenceChangedEventArgs() { Key = _key });
423             }
424         }
425
426     }
427
428     internal static class PreferenceErrorFactory
429     {
430         internal enum PreferenceError
431         {
432             None = ErrorCode.None,
433             OutOfMemory = ErrorCode.OutOfMemory,
434             InvalidParameter = ErrorCode.InvalidParameter,
435             KeyNotAvailable = -0x01100000 | 0x30,
436             IoError = ErrorCode.IoError
437         }
438
439         static internal Exception GetException(int error)
440         {
441             if ((PreferenceError)error == PreferenceError.OutOfMemory)
442             {
443                 return new OutOfMemoryException("Out of memory");
444             }
445             else if ((PreferenceError)error == PreferenceError.InvalidParameter)
446             {
447                 return new ArgumentException("Invalid parameter");
448             }
449             else if ((PreferenceError)error == PreferenceError.KeyNotAvailable)
450             {
451                 return new KeyNotFoundException("Key does not exist in the bundle");
452             }
453             else if ((PreferenceError)error == PreferenceError.IoError)
454             {
455                 return new System.IO.IOException("I/O Error");
456             }
457             else
458             {
459                 return new ArgumentException("Unknown error");
460             }
461         }
462     }
463 }