/*
* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using Tizen.Internals.Errors;
namespace Tizen.Applications
{
///
/// 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.
/// Keys are always text strings and value can be any one of four types: integer, double, string and boolean.
///
public static class Preference
{
private const string LogTag = "Tizen.Applications";
private static Interop.Preference.ChangedCallback s_preferenceChangedCallback;
private static IDictionary s_eventMap = new Dictionary();
static Preference()
{
s_preferenceChangedCallback = (string key, IntPtr userData) =>
{
try
{
s_eventMap[key]?.FireEvent();
}
catch (Exception e)
{
Log.Warn(LogTag, e.Message);
}
};
}
///
/// Retrieves all keys of the application preferences
///
///
/// The list of keys
///
///
///
/// Preference.Set("Option_enabled", true);
/// Preference.Set("active_user", "Joe");
/// Preference.Set("default_volume", 10);
/// Preference.Set("brightness", "0.6");
/// foreach(string key in Preference.Keys)
/// {
/// Console.WriteLine("key {0}", key);
/// }
///
///
public static IEnumerable Keys
{
get
{
var collection = new List();
Interop.Preference.ItemCallback itemsCallback = (string key, IntPtr userData) =>
{
collection.Add(key);
return true;
};
Interop.Preference.ForeachItem(itemsCallback, IntPtr.Zero);
return collection;
}
}
///
/// Gets the event context for the given key.
///
///
/// The preference key
/// The event context of respective key
/// Thrown if the key is not found
/// Thrown if the key is an invalid parameter.
///
///
/// private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e)
/// {
/// Console.WriteLine("key {0}", e.Key);
/// }
///
/// Preference.EventContext context = null;
/// Preference.GetEventContext("active_user").TryGetTarget(out context);
/// if(context != null)
/// {
/// context.Changed += Preference_PreferenceChanged;
/// }
///
/// Preference.Set("active_user", "Poe");
///
/// Preference.GetEventContext("active_user").TryGetTarget(out context);
/// if (context != null)
/// {
/// context.Changed -= Preference_PreferenceChanged;
/// }
///
///
public static WeakReference GetEventContext(string key)
{
if (!s_eventMap.ContainsKey(key))
{
if (Contains(key))
{
s_eventMap[key] = new EventContext(key);
}
else
{
throw PreferenceErrorFactory.GetException((int)PreferenceErrorFactory.PreferenceError.KeyNotAvailable);
}
}
return new WeakReference(s_eventMap[key]);
}
///
/// Checks whether the given key exists in the preference.
///
/// The name of the key to check
/// true if the key exists in the preference, otherwise false
/// Thrown if the key is an invalid parameter.
/// Thrown when method failed due to internal IO error.
///
///
/// Preference.Set("active_user", "Joe");
/// bool exists = Preference.Contains("active_user");
/// if (exists)
/// {
/// string value = Preference.Get("active_user");
/// Console.WriteLine("user {0}", value);
/// }
///
///
public static bool Contains(string key)
{
bool contains;
int ret = Interop.Preference.IsExisting(key, out contains);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to find key");
throw PreferenceErrorFactory.GetException(ret);
}
return contains;
}
///
/// Sets a key-value pair representing the preference.
///
///
/// If the key already exists in the Preference, old value will be overwritten with new value.
/// Data types supported for value are: integer, double, string and bool.
///
/// The name of the key to create/modigy
/// The value corresponding to the key.
/// Thrown if the key is an invalid parameter.
/// Thrown when method failed due to internal IO error.
///
///
/// Preference.Set("Option_enabled", true);
/// Preference.Set("active_user", "Joe");
/// Preference.Set("default_volume", 10);
/// Preference.Set("brightness", "0.6");
///
///
public static void Set(string key, object value)
{
int ret = 0;
if (value is int)
{
ret = Interop.Preference.SetInt(key, (int)value);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to find key");
throw PreferenceErrorFactory.GetException(ret);
}
}
else if (value is double)
{
ret = Interop.Preference.SetDouble(key, (double)value);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to find key");
throw PreferenceErrorFactory.GetException(ret);
}
}
else if (value is string)
{
ret = Interop.Preference.SetString(key, (string)value);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to find key");
throw PreferenceErrorFactory.GetException(ret);
}
}
else if (value is bool)
{
ret = Interop.Preference.SetBoolean(key, (bool)value);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to find key");
throw PreferenceErrorFactory.GetException(ret);
}
}
else
{
Log.Error(LogTag, "Failed to Set");
throw new ArgumentException("Invalid parameter");
}
}
///
/// Gets the value of a preference item with the specified key.
/// Note that this is a generic method.
///
/// The generic type to return.
/// The key of the preference
/// The value of the preference item if it is of the specified generic type.
/// Thrown if the key is not found
/// Thrown if the key is an invalid parameter.
/// Thrown when method failed due to internal IO error.
///
///
/// bool exists = Preference.Contains("active_user");
/// if (exists)
/// {
/// string value = Preference.Get("active_user");
/// Console.WriteLine("user {0}", value);
/// }
///
///
public static T Get(string key)
{
object result = null;
int ret = (int)PreferenceErrorFactory.PreferenceError.None;
if (typeof(T) == typeof(bool))
{
bool val;
ret = Interop.Preference.GetBoolean(key, out val);
result = val;
}
else if (typeof(T) == typeof(int))
{
int val;
ret = Interop.Preference.GetInt(key, out val);
result = val;
}
else if (typeof(T) == typeof(string))
{
string val;
ret = Interop.Preference.GetString(key, out val);
result = val;
}
else if (typeof(T) == typeof(double))
{
double val;
ret = Interop.Preference.GetDouble(key, out val);
result = val;
}
else
{
Log.Error(LogTag, "Failed to remove key");
throw new ArgumentException("Invalid parameter");
}
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to remove key");
throw PreferenceErrorFactory.GetException(ret);
}
return (result != null) ? (T)result : default(T);
}
///
/// Removes any preference value with the given key.
///
/// The key to remove
/// Thrown if the key is not found
/// Thrown when method failed due to internal IO error.
///
///
/// bool exists = Preference.Contains("active_user");
/// if (exists)
/// {
/// string value = Preference.Remove("active_user");
/// }
///
///
public static void Remove(string key)
{
int ret = Interop.Preference.Remove(key);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to remove key");
throw PreferenceErrorFactory.GetException(ret);
}
}
///
/// Removes all key-value pairs from the preference.
///
/// Thrown when method failed due to internal IO error.
///
///
/// Preference.Set("Option_enabled", true);
/// Preference.Set("active_user", "Joe");
/// Preference.Set("default_volume", 10);
/// Preference.Set("brightness", "0.6");
/// Preference.RemoveAll();
///
///
public static void RemoveAll()
{
int ret = Interop.Preference.RemoveAll();
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to remove all keys");
throw PreferenceErrorFactory.GetException(ret);
}
}
private static void AllowChangeNotifications(string key)
{
int ret = Interop.Preference.SetChangedCb(key, s_preferenceChangedCallback, IntPtr.Zero);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to set key notification");
throw PreferenceErrorFactory.GetException(ret);
}
}
private static void DisallowChangeNotifications(string key)
{
int ret = Interop.Preference.UnsetChangedCb(key);
if (ret != (int)PreferenceErrorFactory.PreferenceError.None)
{
Log.Error(LogTag, "Failed to remove key notification");
throw PreferenceErrorFactory.GetException(ret);
}
}
///
/// The class manages event handlers of preference keys. The class enables having event handlers for individual preference keys.
///
public class EventContext
{
private string _key;
internal EventContext(string key)
{
_key = key;
}
///
/// Occurs whenever there is change in the value of preference key.
///
/// Thrown when the key does not exist or when there is an invalid parameter.
/// Thrown when the Bundle instance has been disposed.
///
///
/// private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e)
/// {
/// Console.WriteLine("key {0}", e.Key);
/// }
/// Preference.EventContext context = null;
/// Preference.GetEventContext("active_user").TryGetTarget(out context);
/// if(context != null)
/// {
/// context.Changed += Preference_PreferenceChanged;
/// }
///
/// Preference.Set("active_user", "Poe");
///
/// Preference.GetEventContext("active_user").TryGetTarget(out context);
/// if (context != null)
/// {
/// context.Changed -= Preference_PreferenceChanged;
/// }
///
///
public event EventHandler Changed
{
add
{
if (_changed == null)
{
AllowChangeNotifications(_key);
}
_changed += value;
}
remove
{
_changed -= value;
if (_changed == null)
{
DisallowChangeNotifications(_key);
s_eventMap.Remove(_key);
}
}
}
private event EventHandler _changed;
internal void FireEvent()
{
_changed?.Invoke(null, new PreferenceChangedEventArgs() { Key = _key });
}
}
}
internal static class PreferenceErrorFactory
{
internal enum PreferenceError
{
None = ErrorCode.None,
OutOfMemory = ErrorCode.OutOfMemory,
InvalidParameter = ErrorCode.InvalidParameter,
KeyNotAvailable = -0x01100000 | 0x30,
IoError = ErrorCode.IoError
}
static internal Exception GetException(int error)
{
if ((PreferenceError)error == PreferenceError.OutOfMemory)
{
return new OutOfMemoryException("Out of memory");
}
else if ((PreferenceError)error == PreferenceError.InvalidParameter)
{
return new ArgumentException("Invalid parameter");
}
else if ((PreferenceError)error == PreferenceError.KeyNotAvailable)
{
return new KeyNotFoundException("Key does not exist in the bundle");
}
else if ((PreferenceError)error == PreferenceError.IoError)
{
return new System.IO.IOException("I/O Error");
}
else
{
return new ArgumentException("Unknown error");
}
}
}
}