diff --git a/wa/framework/target/runtime_config.py b/wa/framework/target/runtime_config.py index c82cb3c3..552e4375 100644 --- a/wa/framework/target/runtime_config.py +++ b/wa/framework/target/runtime_config.py @@ -4,7 +4,7 @@ from collections import defaultdict, OrderedDict from wa.framework.exception import ConfigError from wa.framework.plugin import Plugin, Parameter from wa.utils.misc import resolve_cpus, resolve_unique_domain_cpus -from wa.utils.types import caseless_string +from wa.utils.types import caseless_string, enum from devlib.exception import TargetError from devlib.utils.misc import unique @@ -14,10 +14,10 @@ logger = logging.getLogger('RuntimeConfig') class RuntimeParameter(Parameter): - def __init__(self, name, setter, setter_params, **kwargs): + def __init__(self, name, setter, setter_params=None, **kwargs): super(RuntimeParameter, self).__init__(name, **kwargs) self.setter = setter - self.setter_params = setter_params + self.setter_params = setter_params or {} def set(self, obj, value): self.validate_value(self.name, value) @@ -61,6 +61,11 @@ class RuntimeConfig(Plugin): self._target_checked = True self._runtime_params[name].set(self, value) + def set_defaults(self): + for p in self.supported_parameters: + if p.default: + self.set_runtime_parameter(p.name, p.default) + def validate_parameters(self): raise NotImplementedError() @@ -191,7 +196,7 @@ class SysfileValuesRuntimeConfig(RuntimeConfig): if path in obj.sysfile_values: msg = 'Syspath "{}:{}" already specified with a value of "{}"' - raise ConfigError(msg.foramt(path, value, obj.sysfile_values[path][0])) + raise ConfigError(msg.format(path, value, obj.sysfile_values[path][0])) obj.sysfile_values[path] = (value, verify) @@ -804,3 +809,95 @@ class CpuidleRuntimeConfig(RuntimeConfig): if state.name not in common_idle_states: common_idle_states.append(state) return common_idle_states + +ScreenOrientation = enum(['NATURAL', 'LEFT', 'INVERTED', 'RIGHT']) + + +class AndroidRuntimeConfig(RuntimeConfig): + + name = 'rt-android' + + @staticmethod + def set_brightness(obj, value): + if value is not None: + obj.config['brightness'] = value + + @staticmethod + def set_airplane_mode(obj, value): + if value is not None: + obj.config['airplane_mode'] = value + + @staticmethod + def set_rotation(obj, value): + if value is not None: + obj.config['rotation'] = value.value + + @staticmethod + def set_screen_state(obj, value): + if value is not None: + obj.config['screen_on'] = value + + def __init__(self, target): + self.config = defaultdict(dict) + super(AndroidRuntimeConfig, self).__init__(target) + + def initialize(self): + if self.target.os != 'android': + return + + param_name = 'brightness' + self._runtime_params[param_name] = \ + RuntimeParameter(param_name, kind=int, + constraint=lambda x: 0 <= x <= 255, + default=127, + setter=self.set_brightness, + description=""" + Specify the screen brightness to be set for + the device + """) + param_name = 'airplane_mode' + self._runtime_params[param_name] = \ + RuntimeParameter(param_name, kind=bool, + setter=self.set_airplane_mode, + description=""" + Specify whether airplane mode should be + enabled for the device + """) + param_name = 'rotation' + self._runtime_params[param_name] = \ + RuntimeParameter(param_name, kind=ScreenOrientation, + setter=self.set_rotation, + description=""" + Specify the screen orientation for the device + """) + param_name = 'screen_on' + self._runtime_params[param_name] = \ + RuntimeParameter(param_name, kind=bool, + default=True, + setter=self.set_screen_state, + description=""" + Specify whether the device screen should be on + """) + + def check_target(self): + if self.target.os != 'android': + raise ConfigError('Target does not appear to be running Android') + + def validate_parameters(self): + pass + + def commit(self): + if 'airplane_mode' in self.config: + self.target.set_airplane_mode(self.config['airplane_mode']) + if 'brightness' in self.config: + self.target.set_brightness(self.config['brightness']) + if 'rotation' in self.config: + self.target.set_rotation(self.config['rotation']) + if 'screen_on' in self.config: + if self.config['screen_on']: + self.target.ensure_screen_is_on() + else: + self.target.ensure_screen_is_off() + + def clear(self): + self.config = {} diff --git a/wa/framework/target/runtime_parameter_manager.py b/wa/framework/target/runtime_parameter_manager.py index 88a85eac..0c8fc4f4 100644 --- a/wa/framework/target/runtime_parameter_manager.py +++ b/wa/framework/target/runtime_parameter_manager.py @@ -5,7 +5,8 @@ from wa.framework.exception import ConfigError from wa.framework.target.runtime_config import (SysfileValuesRuntimeConfig, HotplugRuntimeConfig, CpufreqRuntimeConfig, - CpuidleRuntimeConfig) + CpuidleRuntimeConfig, + AndroidRuntimeConfig) from wa.utils.types import obj_dict @@ -17,6 +18,7 @@ class RuntimeParameterManager(object): HotplugRuntimeConfig, CpufreqRuntimeConfig, CpuidleRuntimeConfig, + AndroidRuntimeConfig, ] def __init__(self, target): @@ -69,6 +71,7 @@ class RuntimeParameterManager(object): def clear_runtime_parameters(self): for cfg in self.runtime_configs: cfg.clear() + cfg.set_defaults() def get_config_for_name(self, name): for rp_name, rp in self.runtime_params.iteritems(): diff --git a/wa/utils/serializer.py b/wa/utils/serializer.py index 14c3eccf..45fc9d76 100644 --- a/wa/utils/serializer.py +++ b/wa/utils/serializer.py @@ -52,7 +52,7 @@ import dateutil.parser from wa.framework.exception import SerializerSyntaxError from wa.utils.misc import isiterable -from wa.utils.types import regex_type, none_type +from wa.utils.types import regex_type, none_type, level __all__ = [ @@ -78,6 +78,7 @@ POD_TYPES = [ datetime, regex_type, none_type, + level, ] class WAJSONEncoder(_json.JSONEncoder): @@ -87,6 +88,8 @@ class WAJSONEncoder(_json.JSONEncoder): return 'REGEX:{}:{}'.format(obj.flags, obj.pattern) elif isinstance(obj, datetime): return 'DATET:{}'.format(obj.isoformat()) + elif isinstance(obj, level): + return 'LEVEL:{}:{}'.format(obj.name, obj.value) else: return _json.JSONEncoder.default(self, obj) @@ -97,14 +100,18 @@ class WAJSONDecoder(_json.JSONDecoder): d = _json.JSONDecoder.decode(self, s, **kwargs) def try_parse_object(v): - if isinstance(v, basestring) and v.startswith('REGEX:'): - _, flags, pattern = v.split(':', 2) - return re.compile(pattern, int(flags or 0)) - elif isinstance(v, basestring) and v.startswith('DATET:'): - _, pattern = v.split(':', 1) - return dateutil.parser.parse(pattern) - else: - return v + if isinstance(v, basestring): + if v.startswith('REGEX:'): + _, flags, pattern = v.split(':', 2) + return re.compile(pattern, int(flags or 0)) + elif v.startswith('DATET:'): + _, pattern = v.split(':', 1) + return dateutil.parser.parse(pattern) + elif v.startswith('LEVEL:'): + _, name, value = v.split(':', 2) + return level(name, value) + + return v def load_objects(d): pairs = [] @@ -147,6 +154,7 @@ class json(object): _mapping_tag = _yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG _regex_tag = u'tag:wa:regex' +_level_tag = u'tag:wa:level' def _wa_dict_representer(dumper, data): @@ -157,6 +165,9 @@ def _wa_regex_representer(dumper, data): text = '{}:{}'.format(data.flags, data.pattern) return dumper.represent_scalar(_regex_tag, text) +def _wa_level_representer(dumper, data): + text = '{}:{}'.format(data.name, data.level) + return dumper.represent_scalar(_level_tag, text) def _wa_dict_constructor(loader, node): pairs = loader.construct_pairs(node) @@ -173,11 +184,18 @@ def _wa_regex_constructor(loader, node): flags, pattern = value.split(':', 1) return re.compile(pattern, int(flags or 0)) +def _wa_level_constructor(loader, node): + value = loader.construct_scalar(node) + name, value = value.split(':', 1) + return level(name, value) + _yaml.add_representer(OrderedDict, _wa_dict_representer) _yaml.add_representer(regex_type, _wa_regex_representer) +_yaml.add_representer(level, _wa_level_representer) _yaml.add_constructor(_mapping_tag, _wa_dict_constructor) _yaml.add_constructor(_regex_tag, _wa_regex_constructor) +_yaml.add_constructor(_level_tag, _wa_level_constructor) class yaml(object): diff --git a/wa/utils/types.py b/wa/utils/types.py index 2db72597..f299eefb 100644 --- a/wa/utils/types.py +++ b/wa/utils/types.py @@ -554,6 +554,10 @@ def enum(args, start=0, step=1): class Enum(object): + class __metaclass__(type): + def __str__(cls): + return str(cls.levels) + @classmethod def from_pod(cls, pod): lv = level.from_pod(pod)