| Index: build/android/pylib/device/shared_prefs.py
|
| diff --git a/build/android/pylib/device/shared_prefs.py b/build/android/pylib/device/shared_prefs.py
|
| index cb0f1d6e6ad49343e81d0edebea9f04a88118df9..38db76a8924284cf1150e9f12692622efa9879d1 100644
|
| --- a/build/android/pylib/device/shared_prefs.py
|
| +++ b/build/android/pylib/device/shared_prefs.py
|
| @@ -2,390 +2,7 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -"""Helper object to read and modify Shared Preferences from Android apps.
|
| +# pylint: disable=unused-wildcard-import
|
| +# pylint: disable=wildcard-import
|
|
|
| -See e.g.:
|
| - http://developer.android.com/reference/android/content/SharedPreferences.html
|
| -"""
|
| -
|
| -import collections
|
| -import logging
|
| -import posixpath
|
| -
|
| -from xml.etree import ElementTree
|
| -
|
| -
|
| -_XML_DECLARATION = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
|
| -
|
| -
|
| -class BasePref(object):
|
| - """Base class for getting/setting the value of a specific preference type.
|
| -
|
| - Should not be instantiated directly. The SharedPrefs collection will
|
| - instantiate the appropriate subclasses, which directly manipulate the
|
| - underlying xml document, to parse and serialize values according to their
|
| - type.
|
| -
|
| - Args:
|
| - elem: An xml ElementTree object holding the preference data.
|
| -
|
| - Properties:
|
| - tag_name: A string with the tag that must be used for this preference type.
|
| - """
|
| - tag_name = None
|
| -
|
| - def __init__(self, elem):
|
| - if elem.tag != type(self).tag_name:
|
| - raise TypeError('Property %r has type %r, but trying to access as %r' %
|
| - (elem.get('name'), elem.tag, type(self).tag_name))
|
| - self._elem = elem
|
| -
|
| - def __str__(self):
|
| - """Get the underlying xml element as a string."""
|
| - return ElementTree.tostring(self._elem)
|
| -
|
| - def get(self):
|
| - """Get the value of this preference."""
|
| - return self._elem.get('value')
|
| -
|
| - def set(self, value):
|
| - """Set from a value casted as a string."""
|
| - self._elem.set('value', str(value))
|
| -
|
| - @property
|
| - def has_value(self):
|
| - """Check whether the element has a value."""
|
| - return self._elem.get('value') is not None
|
| -
|
| -
|
| -class BooleanPref(BasePref):
|
| - """Class for getting/setting a preference with a boolean value.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <boolean name="featureEnabled" value="false" />
|
| - """
|
| - tag_name = 'boolean'
|
| - VALUES = {'true': True, 'false': False}
|
| -
|
| - def get(self):
|
| - """Get the value as a Python bool."""
|
| - return type(self).VALUES[super(BooleanPref, self).get()]
|
| -
|
| - def set(self, value):
|
| - """Set from a value casted as a bool."""
|
| - super(BooleanPref, self).set('true' if value else 'false')
|
| -
|
| -
|
| -class FloatPref(BasePref):
|
| - """Class for getting/setting a preference with a float value.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <float name="someMetric" value="4.7" />
|
| - """
|
| - tag_name = 'float'
|
| -
|
| - def get(self):
|
| - """Get the value as a Python float."""
|
| - return float(super(FloatPref, self).get())
|
| -
|
| -
|
| -class IntPref(BasePref):
|
| - """Class for getting/setting a preference with an int value.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <int name="aCounter" value="1234" />
|
| - """
|
| - tag_name = 'int'
|
| -
|
| - def get(self):
|
| - """Get the value as a Python int."""
|
| - return int(super(IntPref, self).get())
|
| -
|
| -
|
| -class LongPref(IntPref):
|
| - """Class for getting/setting a preference with a long value.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <long name="aLongCounter" value="1234" />
|
| -
|
| - We use the same implementation from IntPref.
|
| - """
|
| - tag_name = 'long'
|
| -
|
| -
|
| -class StringPref(BasePref):
|
| - """Class for getting/setting a preference with a string value.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <string name="someHashValue">249b3e5af13d4db2</string>
|
| - """
|
| - tag_name = 'string'
|
| -
|
| - def get(self):
|
| - """Get the value as a Python string."""
|
| - return self._elem.text
|
| -
|
| - def set(self, value):
|
| - """Set from a value casted as a string."""
|
| - self._elem.text = str(value)
|
| -
|
| -
|
| -class StringSetPref(StringPref):
|
| - """Class for getting/setting a preference with a set of string values.
|
| -
|
| - The underlying xml element has the form, e.g.:
|
| - <set name="managed_apps">
|
| - <string>com.mine.app1</string>
|
| - <string>com.mine.app2</string>
|
| - <string>com.mine.app3</string>
|
| - </set>
|
| - """
|
| - tag_name = 'set'
|
| -
|
| - def get(self):
|
| - """Get a list with the string values contained."""
|
| - value = []
|
| - for child in self._elem:
|
| - assert child.tag == 'string'
|
| - value.append(child.text)
|
| - return value
|
| -
|
| - def set(self, value):
|
| - """Set from a sequence of values, each casted as a string."""
|
| - for child in list(self._elem):
|
| - self._elem.remove(child)
|
| - for item in value:
|
| - ElementTree.SubElement(self._elem, 'string').text = str(item)
|
| -
|
| -
|
| -_PREF_TYPES = {c.tag_name: c for c in [BooleanPref, FloatPref, IntPref,
|
| - LongPref, StringPref, StringSetPref]}
|
| -
|
| -
|
| -class SharedPrefs(object):
|
| - def __init__(self, device, package, filename):
|
| - """Helper object to read and update "Shared Prefs" of Android apps.
|
| -
|
| - Such files typically look like, e.g.:
|
| -
|
| - <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
| - <map>
|
| - <int name="databaseVersion" value="107" />
|
| - <boolean name="featureEnabled" value="false" />
|
| - <string name="someHashValue">249b3e5af13d4db2</string>
|
| - </map>
|
| -
|
| - Example usage:
|
| -
|
| - prefs = shared_prefs.SharedPrefs(device, 'com.my.app', 'my_prefs.xml')
|
| - prefs.Load()
|
| - prefs.GetString('someHashValue') # => '249b3e5af13d4db2'
|
| - prefs.SetInt('databaseVersion', 42)
|
| - prefs.Remove('featureEnabled')
|
| - prefs.Commit()
|
| -
|
| - The object may also be used as a context manager to automatically load and
|
| - commit, respectively, upon entering and leaving the context.
|
| -
|
| - Args:
|
| - device: A DeviceUtils object.
|
| - package: A string with the package name of the app that owns the shared
|
| - preferences file.
|
| - filename: A string with the name of the preferences file to read/write.
|
| - """
|
| - self._device = device
|
| - self._xml = None
|
| - self._package = package
|
| - self._filename = filename
|
| - self._path = '/data/data/%s/shared_prefs/%s' % (package, filename)
|
| - self._changed = False
|
| -
|
| - def __repr__(self):
|
| - """Get a useful printable representation of the object."""
|
| - return '<{cls} file {filename} for {package} on {device}>'.format(
|
| - cls=type(self).__name__, filename=self.filename, package=self.package,
|
| - device=str(self._device))
|
| -
|
| - def __str__(self):
|
| - """Get the underlying xml document as a string."""
|
| - return _XML_DECLARATION + ElementTree.tostring(self.xml)
|
| -
|
| - @property
|
| - def package(self):
|
| - """Get the package name of the app that owns the shared preferences."""
|
| - return self._package
|
| -
|
| - @property
|
| - def filename(self):
|
| - """Get the filename of the shared preferences file."""
|
| - return self._filename
|
| -
|
| - @property
|
| - def path(self):
|
| - """Get the full path to the shared preferences file on the device."""
|
| - return self._path
|
| -
|
| - @property
|
| - def changed(self):
|
| - """True if properties have changed and a commit would be needed."""
|
| - return self._changed
|
| -
|
| - @property
|
| - def xml(self):
|
| - """Get the underlying xml document as an ElementTree object."""
|
| - if self._xml is None:
|
| - self._xml = ElementTree.Element('map')
|
| - return self._xml
|
| -
|
| - def Load(self):
|
| - """Load the shared preferences file from the device.
|
| -
|
| - A empty xml document, which may be modified and saved on |commit|, is
|
| - created if the file does not already exist.
|
| - """
|
| - if self._device.FileExists(self.path):
|
| - self._xml = ElementTree.fromstring(
|
| - self._device.ReadFile(self.path, as_root=True))
|
| - assert self._xml.tag == 'map'
|
| - else:
|
| - self._xml = None
|
| - self._changed = False
|
| -
|
| - def Clear(self):
|
| - """Clear all of the preferences contained in this object."""
|
| - if self._xml is not None and len(self): # only clear if not already empty
|
| - self._xml = None
|
| - self._changed = True
|
| -
|
| - def Commit(self):
|
| - """Save the current set of preferences to the device.
|
| -
|
| - Only actually saves if some preferences have been modified.
|
| - """
|
| - if not self.changed:
|
| - return
|
| - self._device.RunShellCommand(
|
| - ['mkdir', '-p', posixpath.dirname(self.path)],
|
| - as_root=True, check_return=True)
|
| - self._device.WriteFile(self.path, str(self), as_root=True)
|
| - self._device.KillAll(self.package, exact=True, as_root=True, quiet=True)
|
| - self._changed = False
|
| -
|
| - def __len__(self):
|
| - """Get the number of preferences in this collection."""
|
| - return len(self.xml)
|
| -
|
| - def PropertyType(self, key):
|
| - """Get the type (i.e. tag name) of a property in the collection."""
|
| - return self._GetChild(key).tag
|
| -
|
| - def HasProperty(self, key):
|
| - try:
|
| - self._GetChild(key)
|
| - return True
|
| - except KeyError:
|
| - return False
|
| -
|
| - def GetBoolean(self, key):
|
| - """Get a boolean property."""
|
| - return BooleanPref(self._GetChild(key)).get()
|
| -
|
| - def SetBoolean(self, key, value):
|
| - """Set a boolean property."""
|
| - self._SetPrefValue(key, value, BooleanPref)
|
| -
|
| - def GetFloat(self, key):
|
| - """Get a float property."""
|
| - return FloatPref(self._GetChild(key)).get()
|
| -
|
| - def SetFloat(self, key, value):
|
| - """Set a float property."""
|
| - self._SetPrefValue(key, value, FloatPref)
|
| -
|
| - def GetInt(self, key):
|
| - """Get an int property."""
|
| - return IntPref(self._GetChild(key)).get()
|
| -
|
| - def SetInt(self, key, value):
|
| - """Set an int property."""
|
| - self._SetPrefValue(key, value, IntPref)
|
| -
|
| - def GetLong(self, key):
|
| - """Get a long property."""
|
| - return LongPref(self._GetChild(key)).get()
|
| -
|
| - def SetLong(self, key, value):
|
| - """Set a long property."""
|
| - self._SetPrefValue(key, value, LongPref)
|
| -
|
| - def GetString(self, key):
|
| - """Get a string property."""
|
| - return StringPref(self._GetChild(key)).get()
|
| -
|
| - def SetString(self, key, value):
|
| - """Set a string property."""
|
| - self._SetPrefValue(key, value, StringPref)
|
| -
|
| - def GetStringSet(self, key):
|
| - """Get a string set property."""
|
| - return StringSetPref(self._GetChild(key)).get()
|
| -
|
| - def SetStringSet(self, key, value):
|
| - """Set a string set property."""
|
| - self._SetPrefValue(key, value, StringSetPref)
|
| -
|
| - def Remove(self, key):
|
| - """Remove a preference from the collection."""
|
| - self.xml.remove(self._GetChild(key))
|
| -
|
| - def AsDict(self):
|
| - """Return the properties and their values as a dictionary."""
|
| - d = {}
|
| - for child in self.xml:
|
| - pref = _PREF_TYPES[child.tag](child)
|
| - d[child.get('name')] = pref.get()
|
| - return d
|
| -
|
| - def __enter__(self):
|
| - """Load preferences file from the device when entering a context."""
|
| - self.Load()
|
| - return self
|
| -
|
| - def __exit__(self, exc_type, _exc_value, _traceback):
|
| - """Save preferences file to the device when leaving a context."""
|
| - if not exc_type:
|
| - self.Commit()
|
| -
|
| - def _GetChild(self, key):
|
| - """Get the underlying xml node that holds the property of a given key.
|
| -
|
| - Raises:
|
| - KeyError when the key is not found in the collection.
|
| - """
|
| - for child in self.xml:
|
| - if child.get('name') == key:
|
| - return child
|
| - raise KeyError(key)
|
| -
|
| - def _SetPrefValue(self, key, value, pref_cls):
|
| - """Set the value of a property.
|
| -
|
| - Args:
|
| - key: The key of the property to set.
|
| - value: The new value of the property.
|
| - pref_cls: A subclass of BasePref used to access the property.
|
| -
|
| - Raises:
|
| - TypeError when the key already exists but with a different type.
|
| - """
|
| - try:
|
| - pref = pref_cls(self._GetChild(key))
|
| - old_value = pref.get()
|
| - except KeyError:
|
| - pref = pref_cls(ElementTree.SubElement(
|
| - self.xml, pref_cls.tag_name, {'name': key}))
|
| - old_value = None
|
| - if old_value != value:
|
| - pref.set(value)
|
| - self._changed = True
|
| - logging.info('Setting property: %s', pref)
|
| +from devil.android.sdk.shared_prefs import *
|
|
|