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.
990 def __init__(self, name, parent,
991 id=None, deprecated=False, optional=False, hidden=False, notes=None, sdk_notes=None, ndk_notes=None, ndk_hidden=False):
992 self._name = name # str, e.g. 'ON' or 'OFF'
993 self._id = id # int, e.g. '0'
994 self._deprecated = deprecated # bool
995 self._optional = optional # bool
996 self._hidden = hidden # bool
997 self._ndk_hidden = ndk_hidden # bool
998 self._notes = notes # None or str
999 self._sdk_notes = sdk_notes # None or str
1000 self._ndk_notes = ndk_notes # None or str
1001 self._parent = parent
1008 def deprecated(self):
1009 return self._deprecated
1013 return self._optional
1020 def ndk_hidden(self):
1021 return self._ndk_hidden
1028 def sdk_notes(self):
1029 return self._sdk_notes
1032 def ndk_notes(self):
1033 return self._ndk_notes
1035 def _get_children(self):
1040 A class corresponding to an <enum> element within an <entry>.
1042 Attributes (Read-Only):
1043 parent: An edge to the parent, always an Entry instance.
1044 values: A sequence of EnumValue children.
1045 has_values_with_id: A boolean representing if any of the children have a
1046 non-empty id property.
1048 def __init__(self, parent, values, ids={}, deprecateds=[],
1049 optionals=[], hiddens=[], notes={}, sdk_notes={}, ndk_notes={}, ndk_hiddens=[]):
1051 [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, val in hiddens, \
1052 notes.get(val), sdk_notes.get(val), ndk_notes.get(val), val in ndk_hiddens) \
1055 self._parent = parent
1060 return (i for i in self._values)
1063 def has_values_with_id(self):
1064 return bool(any(i for i in self.values if i.id))
1066 def _get_children(self):
1067 return (i for i in self._values)
1071 A node corresponding to an <entry> element.
1073 Attributes (Read-Only):
1074 parent: An edge to the parent node, which is an InnerNamespace or Kind.
1075 name: The fully qualified name string, e.g. 'android.shading.mode'
1076 name_short: The name attribute from <entry name="mode">, e.g. mode
1077 type: The type attribute from <entry type="bar">
1078 kind: A string ('static', 'dynamic', 'controls') corresponding to the
1080 container: The container attribute from <entry container="array">, or None.
1081 container_sizes: A sequence of size strings or None if container is None.
1082 enum: An Enum instance if the enum attribute is true, None otherwise.
1083 visibility: The visibility of this entry ('system', 'hidden', 'public')
1084 across the system. System entries are only visible in native code
1085 headers. Hidden entries are marked @hide in managed code, while
1086 public entries are visible in the Android SDK.
1087 applied_visibility: As visibility, but always valid, defaulting to 'system'
1088 if no visibility is given for an entry.
1089 applied_ndk_visible: Always valid. Default is 'false'.
1090 Set to 'true' when the visibility implied entry is visible
1092 synthetic: The C-level visibility of this entry ('false', 'true').
1093 Synthetic entries will not be generated into the native metadata
1094 list of entries (in C code). In general a synthetic entry is
1095 glued together at the Java layer from multiple visibiltity=hidden
1097 hwlevel: The lowest hardware level at which the entry is guaranteed
1098 to be supported by the camera device. All devices with higher
1099 hwlevels will also include this entry. None means that the
1100 entry is optional on any hardware level.
1101 deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1102 unreleased version this needs to be removed altogether. If applied
1103 to an entry from an older release, then this means the entry
1104 should be ignored by newer code.
1105 optional: a bool representing the optional attribute, which denotes the entry
1106 is required for hardware level full devices, but optional for other
1107 hardware levels. None if not present.
1108 applied_optional: As optional but always valid, defaulting to False if no
1109 optional attribute is present.
1110 tuple_values: A sequence of strings describing the tuple values,
1111 None if container is not 'tuple'.
1112 description: A string description, or None.
1113 range: A string range, or None.
1114 units: A string units, or None.
1115 tags: A sequence of Tag nodes associated with this Entry.
1116 type_notes: A string describing notes for the type, or None.
1117 typedef: A Typedef associated with this Entry, or None.
1120 Subclass Clone can be used interchangeable with an Entry,
1121 for when we don't care about the underlying type.
1123 parent and tags edges are invalid until after Metadata#construct_graph
1126 def __init__(self, **kwargs):
1128 Instantiate a new Entry node.
1131 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1132 type: A string describing the type, e.g. 'int32'
1133 kind: A string describing the kind, e.g. 'static'
1134 hal_version: A string for the initial HIDL HAL metadata version this entry
1137 Args (if container):
1138 container: A string describing the container, e.g. 'array' or 'tuple'
1139 container_sizes: A list of string sizes if a container, or None otherwise
1141 Args (if container is 'tuple'):
1142 tuple_values: A list of tuple values, e.g. ['width', 'height']
1144 Args (if the 'enum' attribute is true):
1145 enum: A boolean, True if this is an enum, False otherwise
1146 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1147 enum_optionals: A list of optional enum values, e.g. ['OFF']
1148 enum_notes: A dictionary of value->notes strings.
1149 enum_ids: A dictionary of value->id strings.
1152 description: A string with a description of the entry.
1153 range: A string with the range of the values of the entry, e.g. '>= 0'
1154 units: A string with the units of the values, e.g. 'inches'
1155 details: A string with the detailed documentation for the entry
1156 hal_details: A string with the HAL implementation details for the entry
1157 ndk_details: A string with the extra NDK API documentation for the entry=
1158 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1159 type_notes: A string with the notes for the type
1160 visibility: A string describing the visibility, eg 'system', 'hidden',
1162 synthetic: A bool to mark whether this entry is visible only at the Java
1163 layer (True), or at both layers (False = default).
1164 hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1165 deprecated: A bool to mark whether this is @Deprecated at the Java layer
1167 optional: A bool to mark whether optional for non-full hardware devices
1168 typedef: A string corresponding to a typedef's name attribute.
1171 if kwargs.get('type') is None:
1172 print >> sys.stderr, "ERROR: Missing type for entry '%s' kind '%s'" \
1173 %(kwargs.get('name'), kwargs.get('kind'))
1175 # Attributes are Read-Only, but edges may be mutated by
1176 # Metadata, particularly during construct_graph
1178 self._name = kwargs['name']
1179 self._type = kwargs['type']
1180 self._kind = kwargs['kind'] # static, dynamic, or controls
1182 self._init_common(**kwargs)
1193 def hal_major_version(self):
1194 return self._hal_major_version
1197 def hal_minor_version(self):
1198 return self._hal_minor_version
1201 def visibility(self):
1202 return self._visibility
1205 def applied_visibility(self):
1206 return self._visibility or 'system'
1209 def applied_ndk_visible(self):
1210 if self._visibility in ("public", "ndk_public"):
1215 def synthetic(self):
1216 return self._synthetic
1220 return self._hwlevel
1223 def deprecated(self):
1224 return self._deprecated
1226 # TODO: optional should just return hwlevel is None
1229 return self._optional
1232 def applied_optional(self):
1233 return self._optional or False
1236 def name_short(self):
1237 return self.get_name_minimal()
1240 def container(self):
1241 return self._container
1244 def container_sizes(self):
1245 if self._container_sizes is None:
1248 return (i for i in self._container_sizes)
1251 def tuple_values(self):
1252 if self._tuple_values is None:
1255 return (i for i in self._tuple_values)
1258 def description(self):
1259 return self._description
1271 return self._details
1274 def hal_details(self):
1275 return self._hal_details
1278 def ndk_details(self):
1279 return self._ndk_details
1282 def applied_ndk_details(self):
1283 return (self._details or "") + (self._ndk_details or "")
1287 if self._tags is None:
1290 return (i for i in self._tags)
1293 def type_notes(self):
1294 return self._type_notes
1298 return self._typedef
1304 def _get_children(self):
1308 def sort_children(self):
1313 Whether or not this is a Clone instance.
1320 def _init_common(self, **kwargs):
1322 self._parent = None # filled in by Metadata::_construct_entries
1324 self._container = kwargs.get('container')
1325 self._container_sizes = kwargs.get('container_sizes')
1327 hal_version = kwargs.get('hal_version')
1328 if hal_version is None:
1329 self._hal_major_version = 3
1330 self._hal_minor_version = 2
1332 self._hal_major_version = int(hal_version.partition('.')[0])
1333 self._hal_minor_version = int(hal_version.partition('.')[2])
1335 # access these via the 'enum' prop
1336 enum_values = kwargs.get('enum_values')
1337 enum_deprecateds = kwargs.get('enum_deprecateds')
1338 enum_optionals = kwargs.get('enum_optionals')
1339 enum_hiddens = kwargs.get('enum_hiddens')
1340 enum_ndk_hiddens = kwargs.get('enum_ndk_hiddens')
1341 enum_notes = kwargs.get('enum_notes') # { value => notes }
1342 enum_sdk_notes = kwargs.get('enum_sdk_notes') # { value => sdk_notes }
1343 enum_ndk_notes = kwargs.get('enum_ndk_notes') # { value => ndk_notes }
1344 enum_ids = kwargs.get('enum_ids') # { value => notes }
1345 self._tuple_values = kwargs.get('tuple_values')
1347 self._description = kwargs.get('description')
1348 self._range = kwargs.get('range')
1349 self._units = kwargs.get('units')
1350 self._details = kwargs.get('details')
1351 self._hal_details = kwargs.get('hal_details')
1352 self._ndk_details = kwargs.get('ndk_details')
1354 self._tag_ids = kwargs.get('tag_ids', [])
1355 self._tags = None # Filled in by Metadata::_construct_tags
1357 self._type_notes = kwargs.get('type_notes')
1358 self._type_name = kwargs.get('type_name')
1359 self._typedef = None # Filled in by Metadata::_construct_types
1361 if kwargs.get('enum', False):
1362 self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1363 enum_hiddens, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_ndk_hiddens)
1367 self._visibility = kwargs.get('visibility')
1368 self._synthetic = kwargs.get('synthetic', False)
1369 self._hwlevel = kwargs.get('hwlevel')
1370 self._deprecated = kwargs.get('deprecated', False)
1371 self._optional = kwargs.get('optional')
1372 self._ndk_visible = kwargs.get('ndk_visible')
1374 self._property_keys = kwargs
1378 Copy the attributes into a new entry, merging it with the target entry
1381 return MergedEntry(self)
1383 # Helpers for accessing less than the fully qualified name
1385 def get_name_as_list(self):
1387 Returns the name as a list split by a period.
1390 entry.name is 'android.lens.info.shading'
1391 entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1393 return self.name.split(".")
1395 def get_inner_namespace_list(self):
1397 Returns the inner namespace part of the name as a list
1400 entry.name is 'android.lens.info.shading'
1401 entry.get_inner_namespace_list() == ['info']
1403 return self.get_name_as_list()[2:-1]
1405 def get_outer_namespace(self):
1407 Returns the outer namespace as a string.
1410 entry.name is 'android.lens.info.shading'
1411 entry.get_outer_namespace() == 'android'
1414 Since outer namespaces are non-recursive,
1415 and each entry has one, this does not need to be a list.
1417 return self.get_name_as_list()[0]
1419 def get_section(self):
1421 Returns the section as a string.
1424 entry.name is 'android.lens.info.shading'
1425 entry.get_section() == ''
1428 Since outer namespaces are non-recursive,
1429 and each entry has one, this does not need to be a list.
1431 return self.get_name_as_list()[1]
1433 def get_name_minimal(self):
1435 Returns only the last component of the fully qualified name as a string.
1438 entry.name is 'android.lens.info.shading'
1439 entry.get_name_minimal() == 'shading'
1442 entry.name_short it an alias for this
1444 return self.get_name_as_list()[-1]
1446 def get_path_without_name(self):
1448 Returns a string path to the entry, with the name component excluded.
1451 entry.name is 'android.lens.info.shading'
1452 entry.get_path_without_name() == 'android.lens.info'
1454 return ".".join(self.get_name_as_list()[0:-1])
1459 A Node corresponding to a <clone> element. It has all the attributes of an
1460 <entry> element (Entry) plus the additions specified below.
1462 Attributes (Read-Only):
1463 entry: an edge to an Entry object that this targets
1464 target_kind: A string describing the kind of the target entry.
1465 name: a string of the name, same as entry.name
1466 kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1467 for the <clone> element.
1468 type: always None, since a clone cannot override the type.
1470 def __init__(self, entry=None, **kwargs):
1472 Instantiate a new Clone node.
1475 name: A string with the fully qualified name, e.g. 'android.shading.mode'
1476 type: A string describing the type, e.g. 'int32'
1477 kind: A string describing the kind, e.g. 'static'
1478 target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1479 hal_version: A string for the initial HIDL HAL metadata version this entry
1482 Args (if container):
1483 container: A string describing the container, e.g. 'array' or 'tuple'
1484 container_sizes: A list of string sizes if a container, or None otherwise
1486 Args (if container is 'tuple'):
1487 tuple_values: A list of tuple values, e.g. ['width', 'height']
1489 Args (if the 'enum' attribute is true):
1490 enum: A boolean, True if this is an enum, False otherwise
1491 enum_values: A list of value strings, e.g. ['ON', 'OFF']
1492 enum_optionals: A list of optional enum values, e.g. ['OFF']
1493 enum_notes: A dictionary of value->notes strings.
1494 enum_ids: A dictionary of value->id strings.
1497 entry: An edge to the corresponding target Entry.
1498 description: A string with a description of the entry.
1499 range: A string with the range of the values of the entry, e.g. '>= 0'
1500 units: A string with the units of the values, e.g. 'inches'
1501 details: A string with the detailed documentation for the entry
1502 hal_details: A string with the HAL implementation details for the entry
1503 ndk_details: A string with the extra NDK documentation for the entry
1504 tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1505 type_notes: A string with the notes for the type
1508 Note that type is not specified since it has to be the same as the
1511 self._entry = entry # Entry object
1512 self._target_kind = kwargs['target_kind']
1513 self._name = kwargs['name'] # same as entry.name
1514 self._kind = kwargs['kind']
1516 # illegal to override the type, it should be the same as the entry
1518 # the rest of the kwargs are optional
1519 # can be used to override the regular entry data
1520 self._init_common(**kwargs)
1527 def target_kind(self):
1528 return self._target_kind
1532 Whether or not this is a Clone instance.
1539 class MergedEntry(Entry):
1541 A MergedEntry has all the attributes of a Clone and its target Entry merged
1545 Useful when we want to 'unfold' a clone into a real entry by copying out
1546 the target entry data. In this case we don't care about distinguishing
1547 a clone vs an entry.
1549 def __init__(self, entry):
1551 Create a new instance of MergedEntry.
1554 entry: An Entry or Clone instance
1556 props_distinct = ['description', 'units', 'range', 'details',
1557 'hal_details', 'ndk_details', 'tags', 'kind']
1559 for p in props_distinct:
1561 if entry.is_clone():
1562 setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1564 setattr(self, p, getattr(entry, p))
1566 props_common = ['parent', 'name', 'container',
1567 'container_sizes', 'enum',
1578 'hal_major_version',
1582 for p in props_common:
1584 if entry.is_clone():
1585 setattr(self, p, getattr(entry.entry, p))
1587 setattr(self, p, getattr(entry, p))