4 # Copyright (C) 2012 The Android Open Source Project
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
20 A set of classes (models) each closely representing an XML node in the
21 metadata_definitions.xml file.
23 Node: Base class for most nodes.
24 Entry: A node corresponding to <entry> elements.
25 Clone: A node corresponding to <clone> elements.
26 MergedEntry: A node corresponding to either <entry> or <clone> elements.
27 Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
28 InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
29 OuterNamespace: A node corresponding to a <namespace> with <kind> children.
30 Section: A node corresponding to a <section> element.
31 Enum: A class corresponding an <enum> element within an <entry>
32 EnumValue: A class corresponding to a <value> element within an Enum
33 Metadata: Root node that also provides tree construction functionality.
34 Tag: A node corresponding to a top level <tag> element.
35 Typedef: A node corresponding to a <typedef> element under <types>.
40 from collections import OrderedDict
44 Base class for most nodes that are part of the Metadata graph.
46 Attributes (Read-Only):
47 parent: An edge to a parent Node.
48 name: A string describing the name, usually but not always the 'name'
49 attribute of the corresponding XML node.
64 def find_all(self, pred):
66 Find all descendants that match the predicate.
69 pred: a predicate function that acts as a filter for a Node
72 A sequence of all descendants for which pred(node) is true,
73 in a pre-order visit order.
78 if self._get_children() is None:
81 for i in self._get_children():
82 for j in i.find_all(pred):
85 def find_first(self, pred):
87 Find the first descendant that matches the predicate.
90 pred: a predicate function that acts as a filter for a Node
93 The first Node from find_all(pred), or None if there were no results.
95 for i in self.find_all(pred):
100 def find_parent_first(self, pred):
102 Find the first ancestor that matches the predicate.
105 pred: A predicate function that acts as a filter for a Node
108 The first ancestor closest to the node for which pred(node) is true.
110 for i in self.find_parents(pred):
115 def find_parents(self, pred):
117 Find all ancestors that match the predicate.
120 pred: A predicate function that acts as a filter for a Node
123 A sequence of all ancestors (closest to furthest) from the node,
124 where pred(node) is true.
128 while parent is not None:
131 parent = parent.parent
133 def sort_children(self):
135 Sorts the immediate children in-place.
137 self._sort_by_name(self._children)
139 def _sort_by_name(self, what):
140 what.sort(key=lambda x: x.name)
143 return lambda x: x.name
145 # Iterate over all children nodes. None when node doesn't support children.
146 def _get_children(self):
147 return (i for i in self._children)
149 def _children_name_map_matching(self, match=lambda x: True):
151 for i in self._get_children():
157 def _dictionary_by_name(values):
164 def validate_tree(self):
166 Sanity check the tree recursively, ensuring for a node n, all children's
170 True if validation succeeds, False otherwise.
173 children = self._get_children()
177 for child in self._get_children():
178 if child.parent != self:
179 print >> sys.stderr, ("ERROR: Node '%s' doesn't match the parent" + \
180 "(expected: %s, actual %s)") \
181 %(child, self, child.parent)
184 succ = child.validate_tree() and succ
189 return "<%s name='%s'>" %(self.__class__, self.name)
191 class Metadata(Node):
193 A node corresponding to a <metadata> entry.
195 Attributes (Read-Only):
196 parent: An edge to the parent Node. This is always None for Metadata.
197 outer_namespaces: A sequence of immediate OuterNamespace children.
198 tags: A sequence of all Tag instances available in the graph.
199 types: An iterable of all Typedef instances available in the graph.
204 Initialize with no children. Use insert_* functions and then
205 construct_graph() to build up the Metadata from some source.
209 # kind => { name => entry }
210 self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
211 self._entries_ordered = [] # list of ordered Entry/Clone instances
217 self._outer_namespaces = None
222 def outer_namespaces(self):
223 if self._outer_namespaces is None:
226 return (i for i in self._outer_namespaces)
230 return (i for i in self._tags)
234 return (i for i in self._types)
236 def _get_properties(self):
238 for i in self._entries:
241 for i in self._clones:
244 def insert_tag(self, tag, description=""):
246 Insert a tag into the metadata.
249 tag: A string identifier for a tag.
250 description: A string description for a tag.
253 metadata.insert_tag("BC", "Backwards Compatibility for old API")
256 Subsequent calls to insert_tag with the same tag are safe (they will
259 tag_ids = [tg.name for tg in self.tags if tg.name == tag]
261 self._tags.append(Tag(tag, self, description))
263 def insert_type(self, type_name, type_selector="typedef", **kwargs):
265 Insert a type into the metadata.
268 type_name: A type's name
269 type_selector: The selector for the type, e.g. 'typedef'
271 Args (if type_selector == 'typedef'):
272 languages: A map of 'language name' -> 'fully qualified class path'
275 metadata.insert_type('rectangle', 'typedef',
276 { 'java': 'android.graphics.Rect' })
279 Subsequent calls to insert_type with the same type name are safe (they
283 if type_selector != 'typedef':
284 raise ValueError("Unsupported type_selector given " + type_selector)
286 type_names = [tp.name for tp in self.types if tp.name == tp]
288 self._types.append(Typedef(type_name, self, kwargs.get('languages')))
290 def insert_entry(self, entry):
292 Insert an entry into the metadata.
295 entry: A key-value dictionary describing an entry. Refer to
296 Entry#__init__ for the keys required/optional.
299 Subsequent calls to insert_entry with the same entry+kind name are safe
300 (they will be ignored).
303 self._entries.append(e)
304 self._entry_map[e.kind][e.name] = e
305 self._entries_ordered.append(e)
307 def insert_clone(self, clone):
309 Insert a clone into the metadata.
312 clone: A key-value dictionary describing a clone. Refer to
313 Clone#__init__ for the keys required/optional.
316 Subsequent calls to insert_clone with the same clone+kind name are safe
317 (they will be ignored). Also the target entry need not be inserted
318 ahead of the clone entry.
320 # figure out corresponding entry later. allow clone insert, entry insert
322 c = Clone(entry, **clone)
323 self._entry_map[c.kind][c.name] = c
324 self._clones.append(c)
325 self._entries_ordered.append(c)
327 def prune_clones(self):
329 Remove all clones that don't point to an existing entry.
332 This should be called after all insert_entry/insert_clone calls have
336 for p in self._clones:
338 remove_list.append(p)
340 for p in remove_list:
342 # remove from parent's entries list
343 if p.parent is not None:
344 p.parent._entries.remove(p)
345 # remove from parents' _leafs list
346 for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
347 ancestor._leafs.remove(p)
349 # remove from global list
350 self._clones.remove(p)
351 self._entry_map[p.kind].pop(p.name)
352 self._entries_ordered.remove(p)
354 def is_entry_this_kind(self, entry, kind):
356 Check if input entry if of input kind
359 entry: an Entry object
360 kind: a string. Possible values are "static", "dynamic", "controls"
363 A boolean indicating whether input entry is of input kind.
365 if kind not in ("static", "dynamic", "controls"):
366 assert(False), "Unknown kind value " + kind
368 return entry.name in self._entry_map[kind]
370 # After all entries/clones are inserted,
371 # invoke this to generate the parent/child node graph all these objects
372 def construct_graph(self):
374 Generate the graph recursively, after which all Entry nodes will be
375 accessible recursively by crawling through the outer_namespaces sequence.
378 This is safe to be called multiple times at any time. It should be done at
379 least once or there will be no graph.
382 self._construct_tags()
384 self._construct_types()
386 self._construct_clones()
388 self._construct_outer_namespaces()
391 def _construct_tags(self):
392 tag_dict = self._dictionary_by_name(self.tags)
393 for p in self._get_properties():
395 for tag_id in p._tag_ids:
396 tag = tag_dict.get(tag_id)
398 if tag not in p._tags:
401 if p not in tag.entries:
402 tag._entries.append(p)
404 def _construct_types(self):
405 type_dict = self._dictionary_by_name(self.types)
406 for p in self._get_properties():
408 type_node = type_dict.get(p._type_name)
409 p._typedef = type_node
411 if p not in type_node.entries:
412 type_node._entries.append(p)
414 def _construct_clones(self):
415 for p in self._clones:
416 target_kind = p.target_kind
417 target_entry = self._entry_map[target_kind].get(p.name)
418 p._entry = target_entry
420 # should not throw if we pass validation
421 # but can happen when importing obsolete CSV entries
422 if target_entry is None:
423 print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" + \
424 " has no corresponding entry") \
425 %(p.name, p.target_kind)
427 def _construct_outer_namespaces(self):
429 if self._outer_namespaces is None: #the first time this runs
430 self._outer_namespaces = []
432 root = self._dictionary_by_name(self._outer_namespaces)
433 for ons_name, ons in root.iteritems():
436 for p in self._entries_ordered:
437 ons_name = p.get_outer_namespace()
438 ons = root.get(ons_name, OuterNamespace(ons_name, self))
441 if p not in ons._leafs:
444 for ons_name, ons in root.iteritems():
448 self._construct_sections(ons)
450 if ons not in self._outer_namespaces:
451 self._outer_namespaces.append(ons)
455 def _construct_sections(self, outer_namespace):
457 sections_dict = self._dictionary_by_name(outer_namespace.sections)
458 for sec_name, sec in sections_dict.iteritems():
462 for p in outer_namespace._leafs:
463 does_exist = sections_dict.get(p.get_section())
465 sec = sections_dict.get(p.get_section(), \
466 Section(p.get_section(), outer_namespace))
467 sections_dict[p.get_section()] = sec
471 if p not in sec._leafs:
474 for sec_name, sec in sections_dict.iteritems():
476 if not sec.validate_tree():
477 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
478 "construct_sections (start), with section = '%s'")\
481 self._construct_kinds(sec)
483 if sec not in outer_namespace.sections:
484 outer_namespace._sections.append(sec)
486 if not sec.validate_tree():
487 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
488 "construct_sections (end), with section = '%s'") \
491 # 'controls', 'static' 'dynamic'. etc
492 def _construct_kinds(self, section):
493 for kind in section.kinds:
495 section.validate_tree()
497 group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
498 leaf_it = ((k, g) for k, g in group_entry_by_kind)
500 # allow multiple kinds with the same name. merge if adjacent
501 # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
502 # this helps maintain ABI compatibility when adding an entry in a new kind
503 for idx, (kind_name, entry_it) in enumerate(leaf_it):
504 if idx >= len(section._kinds):
505 kind = Kind(kind_name, section)
506 section._kinds.append(kind)
507 section.validate_tree()
509 kind = section._kinds[idx]
512 if p not in kind._leafs:
513 kind._leafs.append(p)
515 for kind in section._kinds:
517 self._construct_inner_namespaces(kind)
519 self._construct_entries(kind)
522 if not section.validate_tree():
523 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
524 "construct_kinds, with kind = '%s'") %(kind)
526 if not kind.validate_tree():
527 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
528 "construct_kinds, with kind = '%s'") %(kind)
530 def _construct_inner_namespaces(self, parent, depth=0):
531 #parent is InnerNamespace or Kind
532 ins_dict = self._dictionary_by_name(parent.namespaces)
533 for name, ins in ins_dict.iteritems():
536 for p in parent._leafs:
537 ins_list = p.get_inner_namespace_list()
539 if len(ins_list) > depth:
540 ins_str = ins_list[depth]
541 ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
542 ins_dict[ins_str] = ins
544 if p not in ins._leafs:
547 for name, ins in ins_dict.iteritems():
549 # construct children INS
550 self._construct_inner_namespaces(ins, depth + 1)
552 # construct children entries
553 self._construct_entries(ins, depth + 1)
555 if ins not in parent.namespaces:
556 parent._namespaces.append(ins)
558 if not ins.validate_tree():
559 print >> sys.stderr, ("ERROR: Failed to validate tree in " + \
560 "construct_inner_namespaces, with ins = '%s'") \
563 # doesnt construct the entries, so much as links them
564 def _construct_entries(self, parent, depth=0):
565 #parent is InnerNamespace or Kind
566 entry_dict = self._dictionary_by_name(parent.entries)
567 for p in parent._leafs:
568 ins_list = p.get_inner_namespace_list()
570 if len(ins_list) == depth:
571 entry = entry_dict.get(p.name, p)
572 entry_dict[p.name] = entry
574 for name, entry in entry_dict.iteritems():
576 old_parent = entry.parent
577 entry._parent = parent
579 if entry not in parent.entries:
580 parent._entries.append(entry)
582 if old_parent is not None and old_parent != parent:
583 print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
585 %(old_parent.name, parent.name, entry.name)
587 def _get_children(self):
588 if self.outer_namespaces is not None:
589 for i in self.outer_namespaces:
592 if self.tags is not None:
598 A tag Node corresponding to a top-level <tag> element.
600 Attributes (Read-Only):
602 id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
603 description: The description of the tag, the contents of the <tag> element.
604 parent: An edge to the parent, which is always the Metadata root node.
605 entries: A sequence of edges to entries/clones that are using this Tag.
607 def __init__(self, name, parent, description=""):
608 self._name = name # 'id' attribute in XML
610 self._description = description
611 self._parent = parent
613 # all entries that have this tag, including clones
614 self._entries = [] # filled in by Metadata#construct_tags
621 def description(self):
622 return self._description
626 return (i for i in self._entries)
628 def _get_children(self):
633 A typedef Node corresponding to a <typedef> element under a top-level <types>.
635 Attributes (Read-Only):
636 name: The name of this typedef as a string.
637 languages: A dictionary of 'language name' -> 'fully qualified class'.
638 parent: An edge to the parent, which is always the Metadata root node.
639 entries: An iterable over all entries which reference this typedef.
641 def __init__(self, name, parent, languages=None):
643 self._parent = parent
645 # all entries that have this typedef
646 self._entries = [] # filled in by Metadata#construct_types
648 self._languages = languages or {}
652 return self._languages
656 return (i for i in self._entries)
658 def _get_children(self):
661 class OuterNamespace(Node):
663 A node corresponding to a <namespace> element under <metadata>
665 Attributes (Read-Only):
666 name: The name attribute of the <namespace name="foo"> element.
667 parent: An edge to the parent, which is always the Metadata root node.
668 sections: A sequence of Section children.
670 def __init__(self, name, parent, sections=[]):
672 self._parent = parent # MetadataSet
673 self._sections = sections[:]
676 self._children = self._sections
680 return (i for i in self._sections)
684 A node corresponding to a <section> element under <namespace>
686 Attributes (Read-Only):
687 name: The name attribute of the <section name="foo"> element.
688 parent: An edge to the parent, which is always an OuterNamespace instance.
689 description: A string description of the section, or None.
690 kinds: A sequence of Kind children.
691 merged_kinds: A sequence of virtual Kind children,
692 with each Kind's children merged by the kind.name
693 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
695 def __init__(self, name, parent, description=None, kinds=[]):
697 self._parent = parent
698 self._description = description
699 self._kinds = kinds[:]
704 def description(self):
705 return self._description
709 return (i for i in self._kinds)
712 def hal_versions(self):
714 for i in self._kinds:
715 for entry in i.entries:
716 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
717 for namespace in i.namespaces:
718 hal_versions.update(namespace.hal_versions)
721 def sort_children(self):
723 # order is always controls,static,dynamic
724 find_child = lambda x: [i for i in self._get_children() if i.name == x]
725 new_lst = find_child('controls') \
726 + find_child('static') \
727 + find_child('dynamic')
728 self._kinds = new_lst
731 def _get_children(self):
732 return (i for i in self.kinds)
735 def merged_kinds(self):
737 def aggregate_by_name(acc, el):
738 existing = [i for i in acc if i.name == el.name]
742 k = Kind(el.name, el.parent)
745 k._namespaces.extend(el._namespaces)
746 k._entries.extend(el._entries)
750 new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
752 for k in new_kinds_lst:
755 def combine_kinds_into_single_node(self):
757 Combines the section's Kinds into a single node.
759 Combines all the children (kinds) of this section into a single
763 A new Kind node that collapses all Kind siblings into one, combining
764 all their children together.
766 For example, given self.kinds == [ x, y ]
772 a new instance z is returned in this example.
775 The children of the kinds are the same references as before, that is
776 their parents will point to the old parents and not to the new parent.
778 combined = Kind(name="combined", parent=self)
780 for k in self._get_children():
781 combined._namespaces.extend(k.namespaces)
782 combined._entries.extend(k.entries)
788 A node corresponding to one of: <static>,<dynamic>,<controls> under a
791 Attributes (Read-Only):
792 name: A string which is one of 'static', 'dynamic, or 'controls'.
793 parent: An edge to the parent, which is always a Section instance.
794 namespaces: A sequence of InnerNamespace children.
795 entries: A sequence of Entry/Clone children.
796 merged_entries: A sequence of MergedEntry virtual nodes from entries
798 def __init__(self, name, parent):
800 self._parent = parent
801 self._namespaces = []
807 def namespaces(self):
808 return self._namespaces
815 def merged_entries(self):
816 for i in self.entries:
819 def sort_children(self):
820 self._namespaces.sort(key=self._get_name())
821 self._entries.sort(key=self._get_name())
823 def _get_children(self):
824 for i in self.namespaces:
826 for i in self.entries:
829 def combine_children_by_name(self):
831 Combine multiple children with the same name into a single node.
834 A new Kind where all of the children with the same name were combined.
850 The returned Kind will look like this:
859 This operation is not recursive. To combine the grandchildren and other
860 ancestors, call this method on the ancestor nodes.
862 return Kind._combine_children_by_name(self, new_type=type(self))
864 # new_type is either Kind or InnerNamespace
866 def _combine_children_by_name(self, new_type):
867 new_ins_dict = OrderedDict()
868 new_ent_dict = OrderedDict()
870 for ins in self.namespaces:
871 new_ins = new_ins_dict.setdefault(ins.name,
872 InnerNamespace(ins.name, parent=self))
873 new_ins._namespaces.extend(ins.namespaces)
874 new_ins._entries.extend(ins.entries)
876 for ent in self.entries:
877 new_ent = new_ent_dict.setdefault(ent.name,
880 kind = new_type(self.name, self.parent)
881 kind._namespaces = new_ins_dict.values()
882 kind._entries = new_ent_dict.values()
886 class InnerNamespace(Node):
888 A node corresponding to a <namespace> which is an ancestor of a Kind.
889 These namespaces may have other namespaces recursively, or entries as leafs.
891 Attributes (Read-Only):
892 name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
893 parent: An edge to the parent, which is an InnerNamespace or a Kind.
894 namespaces: A sequence of InnerNamespace children.
895 entries: A sequence of Entry/Clone children.
896 merged_entries: A sequence of MergedEntry virtual nodes from entries
897 hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
899 def __init__(self, name, parent):
901 self._parent = parent
902 self._namespaces = []
907 def namespaces(self):
908 return self._namespaces
915 def hal_versions(self):
917 for entry in self.entries:
918 hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
919 for namespace in self.namespaces:
920 hal_versions.update(namespace.hal_versions)
924 def merged_entries(self):
925 for i in self.entries:
928 def sort_children(self):
929 self._namespaces.sort(key=self._get_name())
930 self._entries.sort(key=self._get_name())
932 def _get_children(self):
933 for i in self.namespaces:
935 for i in self.entries:
938 def combine_children_by_name(self):
940 Combine multiple children with the same name into a single node.
943 A new InnerNamespace where all of the children with the same name were
948 Given an InnerNamespace i:
960 The returned InnerNamespace will look like this:
969 This operation is not recursive. To combine the grandchildren and other
970 ancestors, call this method on the ancestor nodes.
972 return Kind._combine_children_by_name(self, new_type=type(self))
974 class EnumValue(Node):
976 A class corresponding to a <value> element within an <enum> within an <entry>.
978 Attributes (Read-Only):
979 name: A string, e.g. 'ON' or 'OFF'
980 id: An optional numeric string, e.g. '0' or '0xFF'
981 deprecated: A boolean, True if the enum should be deprecated.
983 hidden: A boolean, True if the enum should be hidden.
984 ndk_hidden: A boolean, True if the enum should be hidden in NDK
985 notes: A string describing the notes, or None.
986 sdk_notes: A string describing extra notes for public SDK only
987 ndk_notes: A string describing extra notes for public NDK only
988 parent: An edge to the parent, always an Enum instance.
989 hal_major_version: The major HIDL HAL version this value was first added in
990 hal_minor_version: The minor HIDL HAL version this value was first added in
992 def __init__(self, name, parent,
993 id=None, deprecated=False, optional=False, hidden=False, notes=None, sdk_notes=None, ndk_notes=None, ndk_hidden=False, hal_version='3.2'):
994 self._name = name # str, e.g. 'ON' or 'OFF'
995 self._id = id # int, e.g. '0'
996 self._deprecated = deprecated # bool
997 self._optional = optional # bool
998 self._hidden = hidden # bool
999 self._ndk_hidden = ndk_hidden # bool
1000 self._notes = notes # None or str
1001 self._sdk_notes = sdk_notes # None or str
1002 self._ndk_notes = ndk_notes # None or str
1003 self._parent = parent
1004 if hal_version is None:
1005 if parent is not None and parent.parent is not None:
1006 self._hal_major_version = parent.parent.hal_major_version
1007 self._hal_minor_version = parent.parent.hal_minor_version
1009 self._hal_major_version = 3
1010 self._hal_minor_version = 2
1012 self._hal_major_version = int(hal_version.partition('.')[0])
1013 self._hal_minor_version = int(hal_version.partition('.')[2])
1020 def deprecated(self):
1021 return self._deprecated
1025 return self._optional
1032 def ndk_hidden(self):
1033 return self._ndk_hidden
1040 def sdk_notes(self):
1041 return self._sdk_notes
1044 def ndk_notes(self):
1045 return self._ndk_notes
1048 def hal_major_version(self):
1049 return self._hal_major_version
1052 def hal_minor_version(self):
1053 return self._hal_minor_version
1055 def _get_children(self):
1060 A class corresponding to an <enum> element within an <entry>.
1062 Attributes (Read-Only):
1063 parent: An edge to the parent, always an Entry instance.
1064 values: A sequence of EnumValue children.
1065 has_values_with_id: A boolean representing if any of the children have a
1066 non-empty id property.
1068 def __init__(self, parent, values, ids={}, deprecateds=[],
1069 optionals=[], hiddens=[], notes={}, sdk_notes={}, ndk_notes={}, ndk_hiddens=[], hal_versions={}):
1070 self._parent = parent
1073 [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, val in hiddens, \
1074 notes.get(val), sdk_notes.get(val), ndk_notes.get(val), val in ndk_hiddens, hal_versions.get(val)) \
1079 return (i for i in self._values)
1082 def has_values_with_id(self):
1083 return bool(any(i for i in self.values if i.id))
1085 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1086 return bool(any(i for i in self.values if i.hal_major_version == hal_major_version and i.hal_minor_version == hal_minor_version))
1088 def _get_children(self):
1089 return (i for i in self._values)
1093 A node corresponding to an <entry> element.
1095 Attributes (Read-Only):
1096 parent: An edge to the parent node, which is an InnerNamespace or Kind.
1097 name: The fully qualified name string, e.g. 'android.shading.mode'
1098 name_short: The name attribute from <entry name="mode">, e.g. mode
1099 type: The type attribute from <entry type="bar">
1100 kind: A string ('static', 'dynamic', 'controls') corresponding to the
1102 container: The container attribute from <entry container="array">, or None.
1103 container_sizes: A sequence of size strings or None if container is None.
1104 enum: An Enum instance if the enum attribute is true, None otherwise.
1105 visibility: The visibility of this entry ('system', 'hidden', 'public')
1106 across the system. System entries are only visible in native code
1107 headers. Hidden entries are marked @hide in managed code, while
1108 public entries are visible in the Android SDK.
1109 applied_visibility: As visibility, but always valid, defaulting to 'system'
1110 if no visibility is given for an entry.
1111 applied_ndk_visible: Always valid. Default is 'false'.
1112 Set to 'true' when the visibility implied entry is visible
1114 synthetic: The C-level visibility of this entry ('false', 'true').
1115 Synthetic entries will not be generated into the native metadata
1116 list of entries (in C code). In general a synthetic entry is
1117 glued together at the Java layer from multiple visibiltity=hidden
1119 hwlevel: The lowest hardware level at which the entry is guaranteed
1120 to be supported by the camera device. All devices with higher
1121 hwlevels will also include this entry. None means that the
1122 entry is optional on any hardware level.
1123 deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1124 unreleased version this needs to be removed altogether. If applied
1125 to an entry from an older release, then this means the entry
1126 should be ignored by newer code.
1127 optional: a bool representing the optional attribute, which denotes the entry
1128 is required for hardware level full devices, but optional for other
1129 hardware levels. None if not present.
1130 applied_optional: As optional but always valid, defaulting to False if no
1131 optional attribute is present.
1132 tuple_values: A sequence of strings describing the tuple values,
1133 None if container is not 'tuple'.
1134 description: A string description, or None.
1135 range: A string range, or None.
1136 units: A string units, or None.
1137 tags: A sequence of Tag nodes associated with this Entry.
1138 type_notes: A string describing notes for the type, or None.
1139 typedef: A Typedef associated with this Entry, or None.
1142 Subclass Clone can be used interchangeable with an Entry,
1143 for when we don't care about the underlying type.
1145 parent and tags edges are invalid until after Metadata#construct_graph
1148 def __init__(self, **kwargs):
1150 Instantiate a new Entry node.
1153 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1154 type: A string describing the type, e.g. 'int32'
1155 kind: A string describing the kind, e.g. 'static'
1156 hal_version: A string for the initial HIDL HAL metadata version this entry
1159 Args (if container):
1160 container: A string describing the container, e.g. 'array' or 'tuple'
1161 container_sizes: A list of string sizes if a container, or None otherwise
1163 Args (if container is 'tuple'):
1164 tuple_values: A list of tuple values, e.g. ['width', 'height']
1166 Args (if the 'enum' attribute is true):
1167 enum: A boolean, True if this is an enum, False otherwise
1168 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1169 enum_optionals: A list of optional enum values, e.g. ['OFF']
1170 enum_notes: A dictionary of value->notes strings.
1171 enum_ids: A dictionary of value->id strings.
1172 enum_hal_versions: A dictionary of value->hal version strings
1175 description: A string with a description of the entry.
1176 range: A string with the range of the values of the entry, e.g. '>= 0'
1177 units: A string with the units of the values, e.g. 'inches'
1178 details: A string with the detailed documentation for the entry
1179 hal_details: A string with the HAL implementation details for the entry
1180 ndk_details: A string with the extra NDK API documentation for the entry=
1181 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1182 type_notes: A string with the notes for the type
1183 visibility: A string describing the visibility, eg 'system', 'hidden',
1185 synthetic: A bool to mark whether this entry is visible only at the Java
1186 layer (True), or at both layers (False = default).
1187 hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1188 deprecated: A bool to mark whether this is @Deprecated at the Java layer
1190 optional: A bool to mark whether optional for non-full hardware devices
1191 typedef: A string corresponding to a typedef's name attribute.
1194 if kwargs.get('type') is None:
1195 print >> sys.stderr, "ERROR: Missing type for entry '%s' kind '%s'" \
1196 %(kwargs.get('name'), kwargs.get('kind'))
1198 # Attributes are Read-Only, but edges may be mutated by
1199 # Metadata, particularly during construct_graph
1201 self._name = kwargs['name']
1202 self._type = kwargs['type']
1203 self._kind = kwargs['kind'] # static, dynamic, or controls
1205 self._init_common(**kwargs)
1216 def hal_major_version(self):
1217 return self._hal_major_version
1220 def hal_minor_version(self):
1221 return self._hal_minor_version
1224 def visibility(self):
1225 return self._visibility
1228 def applied_visibility(self):
1229 return self._visibility or 'system'
1232 def applied_ndk_visible(self):
1233 if self._visibility in ("public", "ndk_public"):
1238 def synthetic(self):
1239 return self._synthetic
1243 return self._hwlevel
1246 def deprecated(self):
1247 return self._deprecated
1249 # TODO: optional should just return hwlevel is None
1252 return self._optional
1255 def applied_optional(self):
1256 return self._optional or False
1259 def name_short(self):
1260 return self.get_name_minimal()
1263 def container(self):
1264 return self._container
1267 def container_sizes(self):
1268 if self._container_sizes is None:
1271 return (i for i in self._container_sizes)
1274 def tuple_values(self):
1275 if self._tuple_values is None:
1278 return (i for i in self._tuple_values)
1281 def description(self):
1282 return self._description
1294 return self._details
1297 def hal_details(self):
1298 return self._hal_details
1301 def ndk_details(self):
1302 return self._ndk_details
1305 def applied_ndk_details(self):
1306 return (self._details or "") + (self._ndk_details or "")
1310 if self._tags is None:
1313 return (i for i in self._tags)
1316 def type_notes(self):
1317 return self._type_notes
1321 return self._typedef
1327 def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1328 if self._enum is not None:
1329 return self._enum.has_new_values_added_in_hal_version(hal_major_version,hal_minor_version)
1333 def _get_children(self):
1337 def sort_children(self):
1342 Whether or not this is a Clone instance.
1349 def _init_common(self, **kwargs):
1351 self._parent = None # filled in by Metadata::_construct_entries
1353 self._container = kwargs.get('container')
1354 self._container_sizes = kwargs.get('container_sizes')
1356 hal_version = kwargs.get('hal_version')
1357 if hal_version is None:
1358 self._hal_major_version = 3
1359 self._hal_minor_version = 2
1361 self._hal_major_version = int(hal_version.partition('.')[0])
1362 self._hal_minor_version = int(hal_version.partition('.')[2])
1364 # access these via the 'enum' prop
1365 enum_values = kwargs.get('enum_values')
1366 enum_deprecateds = kwargs.get('enum_deprecateds')
1367 enum_optionals = kwargs.get('enum_optionals')
1368 enum_hiddens = kwargs.get('enum_hiddens')
1369 enum_ndk_hiddens = kwargs.get('enum_ndk_hiddens')
1370 enum_notes = kwargs.get('enum_notes') # { value => notes }
1371 enum_sdk_notes = kwargs.get('enum_sdk_notes') # { value => sdk_notes }
1372 enum_ndk_notes = kwargs.get('enum_ndk_notes') # { value => ndk_notes }
1373 enum_ids = kwargs.get('enum_ids') # { value => notes }
1374 enum_hal_versions = kwargs.get('enum_hal_versions') # { value => hal_versions }
1376 self._tuple_values = kwargs.get('tuple_values')
1378 self._description = kwargs.get('description')
1379 self._range = kwargs.get('range')
1380 self._units = kwargs.get('units')
1381 self._details = kwargs.get('details')
1382 self._hal_details = kwargs.get('hal_details')
1383 self._ndk_details = kwargs.get('ndk_details')
1385 self._tag_ids = kwargs.get('tag_ids', [])
1386 self._tags = None # Filled in by Metadata::_construct_tags
1388 self._type_notes = kwargs.get('type_notes')
1389 self._type_name = kwargs.get('type_name')
1390 self._typedef = None # Filled in by Metadata::_construct_types
1392 if kwargs.get('enum', False):
1393 self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1394 enum_hiddens, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_ndk_hiddens, enum_hal_versions)
1398 self._visibility = kwargs.get('visibility')
1399 self._synthetic = kwargs.get('synthetic', False)
1400 self._hwlevel = kwargs.get('hwlevel')
1401 self._deprecated = kwargs.get('deprecated', False)
1402 self._optional = kwargs.get('optional')
1403 self._ndk_visible = kwargs.get('ndk_visible')
1405 self._property_keys = kwargs
1409 Copy the attributes into a new entry, merging it with the target entry
1412 return MergedEntry(self)
1414 # Helpers for accessing less than the fully qualified name
1416 def get_name_as_list(self):
1418 Returns the name as a list split by a period.
1421 entry.name is 'android.lens.info.shading'
1422 entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1424 return self.name.split(".")
1426 def get_inner_namespace_list(self):
1428 Returns the inner namespace part of the name as a list
1431 entry.name is 'android.lens.info.shading'
1432 entry.get_inner_namespace_list() == ['info']
1434 return self.get_name_as_list()[2:-1]
1436 def get_outer_namespace(self):
1438 Returns the outer namespace as a string.
1441 entry.name is 'android.lens.info.shading'
1442 entry.get_outer_namespace() == 'android'
1445 Since outer namespaces are non-recursive,
1446 and each entry has one, this does not need to be a list.
1448 return self.get_name_as_list()[0]
1450 def get_section(self):
1452 Returns the section as a string.
1455 entry.name is 'android.lens.info.shading'
1456 entry.get_section() == ''
1459 Since outer namespaces are non-recursive,
1460 and each entry has one, this does not need to be a list.
1462 return self.get_name_as_list()[1]
1464 def get_name_minimal(self):
1466 Returns only the last component of the fully qualified name as a string.
1469 entry.name is 'android.lens.info.shading'
1470 entry.get_name_minimal() == 'shading'
1473 entry.name_short it an alias for this
1475 return self.get_name_as_list()[-1]
1477 def get_path_without_name(self):
1479 Returns a string path to the entry, with the name component excluded.
1482 entry.name is 'android.lens.info.shading'
1483 entry.get_path_without_name() == 'android.lens.info'
1485 return ".".join(self.get_name_as_list()[0:-1])
1490 A Node corresponding to a <clone> element. It has all the attributes of an
1491 <entry> element (Entry) plus the additions specified below.
1493 Attributes (Read-Only):
1494 entry: an edge to an Entry object that this targets
1495 target_kind: A string describing the kind of the target entry.
1496 name: a string of the name, same as entry.name
1497 kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1498 for the <clone> element.
1499 type: always None, since a clone cannot override the type.
1501 def __init__(self, entry=None, **kwargs):
1503 Instantiate a new Clone node.
1506 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1507 type: A string describing the type, e.g. 'int32'
1508 kind: A string describing the kind, e.g. 'static'
1509 target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1510 hal_version: A string for the initial HIDL HAL metadata version this entry
1513 Args (if container):
1514 container: A string describing the container, e.g. 'array' or 'tuple'
1515 container_sizes: A list of string sizes if a container, or None otherwise
1517 Args (if container is 'tuple'):
1518 tuple_values: A list of tuple values, e.g. ['width', 'height']
1520 Args (if the 'enum' attribute is true):
1521 enum: A boolean, True if this is an enum, False otherwise
1522 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1523 enum_optionals: A list of optional enum values, e.g. ['OFF']
1524 enum_notes: A dictionary of value->notes strings.
1525 enum_ids: A dictionary of value->id strings.
1528 entry: An edge to the corresponding target Entry.
1529 description: A string with a description of the entry.
1530 range: A string with the range of the values of the entry, e.g. '>= 0'
1531 units: A string with the units of the values, e.g. 'inches'
1532 details: A string with the detailed documentation for the entry
1533 hal_details: A string with the HAL implementation details for the entry
1534 ndk_details: A string with the extra NDK documentation for the entry
1535 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1536 type_notes: A string with the notes for the type
1539 Note that type is not specified since it has to be the same as the
1542 self._entry = entry # Entry object
1543 self._target_kind = kwargs['target_kind']
1544 self._name = kwargs['name'] # same as entry.name
1545 self._kind = kwargs['kind']
1547 # illegal to override the type, it should be the same as the entry
1549 # the rest of the kwargs are optional
1550 # can be used to override the regular entry data
1551 self._init_common(**kwargs)
1558 def target_kind(self):
1559 return self._target_kind
1563 Whether or not this is a Clone instance.
1570 class MergedEntry(Entry):
1572 A MergedEntry has all the attributes of a Clone and its target Entry merged
1576 Useful when we want to 'unfold' a clone into a real entry by copying out
1577 the target entry data. In this case we don't care about distinguishing
1578 a clone vs an entry.
1580 def __init__(self, entry):
1582 Create a new instance of MergedEntry.
1585 entry: An Entry or Clone instance
1587 props_distinct = ['description', 'units', 'range', 'details',
1588 'hal_details', 'ndk_details', 'tags', 'kind']
1590 for p in props_distinct:
1592 if entry.is_clone():
1593 setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1595 setattr(self, p, getattr(entry, p))
1597 props_common = ['parent', 'name', 'container',
1598 'container_sizes', 'enum',
1609 'hal_major_version',
1613 for p in props_common:
1615 if entry.is_clone():
1616 setattr(self, p, getattr(entry.entry, p))
1618 setattr(self, p, getattr(entry, p))