Source code
Revision control
Copy as Markdown
Other Tools
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utility functions for modifying an app's settings file using JSON."""
import json
import logging
def UnicodeToStr(data):
"""Recursively converts any Unicode to Python strings.
Args:
data: The data to be converted.
Return:
A copy of the given data, but with instances of Unicode converted to Python
strings.
"""
if isinstance(data, dict):
return {
UnicodeToStr(key): UnicodeToStr(value)
for key, value in data.items()
}
elif isinstance(data, list):
return [UnicodeToStr(element) for element in data]
try:
# Python-2 compatibility.
if isinstance(data, unicode):
return data.encode('utf-8')
except NameError:
# Strings are already unicode in python3.
pass
return data
def ExtractSettingsFromJson(filepath):
"""Extracts the settings data from the given JSON file.
Args:
filepath: The path to the JSON file to read.
Return:
The data read from the JSON file with strings converted to Python strings.
"""
# json.load() loads strings as unicode, which causes issues when trying
# to edit string values in preference files, so convert to Python strings
with open(filepath) as prefs_file:
return UnicodeToStr(json.load(prefs_file))
def ApplySharedPreferenceSetting(shared_pref, setting):
"""Applies the given app settings to the given device.
Modifies an installed app's settings by modifying its shared preference
settings file. Provided settings data must be a settings dictionary,
which are in the following format:
{
"package": "com.example.package",
"filename": "AppSettingsFile.xml",
"supports_encrypted_path": true,
"set": {
"SomeBoolToSet": true,
"SomeStringToSet": "StringValue",
},
"remove": [
"list",
"of",
"keys",
"to",
"remove",
]
}
Example JSON files that can be read with ExtractSettingsFromJson and passed to
this function are in //chrome/android/shared_preference_files/test/.
Args:
shared_pref: The devil SharedPrefs object for the device the settings will
be applied to.
setting: A settings dictionary to apply.
"""
shared_pref.Load()
for key in setting.get('remove', []):
try:
shared_pref.Remove(key)
except KeyError:
logging.warning("Attempted to remove non-existent key %s", key)
for key, value in setting.get('set', {}).items():
is_set = False
if not is_set and isinstance(value, bool):
shared_pref.SetBoolean(key, value)
is_set = True
try:
# Python-2 compatibility.
if not is_set and isinstance(value, basestring):
shared_pref.SetString(key, value)
is_set = True
if not is_set and (isinstance(value, long) or isinstance(value, int)):
shared_pref.SetLong(key, value)
is_set = True
except NameError:
if not is_set and isinstance(value, str):
shared_pref.SetString(key, value)
is_set = True
if not is_set and isinstance(value, int):
shared_pref.SetLong(key, value)
is_set = True
if not is_set and isinstance(value, list):
shared_pref.SetStringSet(key, value)
is_set = True
if not is_set:
raise ValueError("Given invalid value type %s for key %s" % (
str(type(value)), key))
shared_pref.Commit()