xref: /aosp_15_r20/system/media/camera/docs/metadata_helpers.py (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker#
2*b9df5ad1SAndroid Build Coastguard Worker# Copyright (C) 2012 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker#
4*b9df5ad1SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker#
8*b9df5ad1SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker#
10*b9df5ad1SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker# limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker#
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker"""
18*b9df5ad1SAndroid Build Coastguard WorkerA set of helpers for rendering Mako templates with a Metadata model.
19*b9df5ad1SAndroid Build Coastguard Worker"""
20*b9df5ad1SAndroid Build Coastguard Worker
21*b9df5ad1SAndroid Build Coastguard Workerimport metadata_model
22*b9df5ad1SAndroid Build Coastguard Workerimport re
23*b9df5ad1SAndroid Build Coastguard Workerimport markdown
24*b9df5ad1SAndroid Build Coastguard Workerimport textwrap
25*b9df5ad1SAndroid Build Coastguard Workerimport sys
26*b9df5ad1SAndroid Build Coastguard Workerimport bs4
27*b9df5ad1SAndroid Build Coastguard Worker# Monkey-patch BS4. WBR element must not have an end tag.
28*b9df5ad1SAndroid Build Coastguard Workerbs4.builder.HTMLTreeBuilder.empty_element_tags.add("wbr")
29*b9df5ad1SAndroid Build Coastguard Worker
30*b9df5ad1SAndroid Build Coastguard Workerfrom collections import OrderedDict, defaultdict
31*b9df5ad1SAndroid Build Coastguard Workerfrom operator import itemgetter
32*b9df5ad1SAndroid Build Coastguard Workerfrom os import path
33*b9df5ad1SAndroid Build Coastguard Worker
34*b9df5ad1SAndroid Build Coastguard Worker# Relative path from HTML file to the base directory used by <img> tags
35*b9df5ad1SAndroid Build Coastguard WorkerIMAGE_SRC_METADATA="images/camera2/metadata/"
36*b9df5ad1SAndroid Build Coastguard Worker
37*b9df5ad1SAndroid Build Coastguard Worker# Prepend this path to each <img src="foo"> in javadocs
38*b9df5ad1SAndroid Build Coastguard WorkerJAVADOC_IMAGE_SRC_METADATA="/reference/" + IMAGE_SRC_METADATA
39*b9df5ad1SAndroid Build Coastguard WorkerNDKDOC_IMAGE_SRC_METADATA="../" + IMAGE_SRC_METADATA
40*b9df5ad1SAndroid Build Coastguard Worker
41*b9df5ad1SAndroid Build Coastguard Worker#Corresponds to Android Q, where the camera VNDK was added (minor version 4 and vndk version 29).
42*b9df5ad1SAndroid Build Coastguard Worker# Minor version and vndk version must correspond to the same release
43*b9df5ad1SAndroid Build Coastguard WorkerFRAMEWORK_CAMERA_VNDK_HAL_MINOR_VERSION = 4
44*b9df5ad1SAndroid Build Coastguard WorkerFRAMEWORK_CAMERA_VNDK_STARTING_VERSION =  29
45*b9df5ad1SAndroid Build Coastguard Worker
46*b9df5ad1SAndroid Build Coastguard Worker_context_buf = None
47*b9df5ad1SAndroid Build Coastguard Worker_enum = None
48*b9df5ad1SAndroid Build Coastguard Worker
49*b9df5ad1SAndroid Build Coastguard Workerdef _is_sec_or_ins(x):
50*b9df5ad1SAndroid Build Coastguard Worker  return isinstance(x, metadata_model.Section) or    \
51*b9df5ad1SAndroid Build Coastguard Worker         isinstance(x, metadata_model.InnerNamespace)
52*b9df5ad1SAndroid Build Coastguard Worker
53*b9df5ad1SAndroid Build Coastguard Worker##
54*b9df5ad1SAndroid Build Coastguard Worker## Metadata Helpers
55*b9df5ad1SAndroid Build Coastguard Worker##
56*b9df5ad1SAndroid Build Coastguard Worker
57*b9df5ad1SAndroid Build Coastguard Workerdef find_all_sections(root):
58*b9df5ad1SAndroid Build Coastguard Worker  """
59*b9df5ad1SAndroid Build Coastguard Worker  Find all descendants that are Section or InnerNamespace instances.
60*b9df5ad1SAndroid Build Coastguard Worker
61*b9df5ad1SAndroid Build Coastguard Worker  Args:
62*b9df5ad1SAndroid Build Coastguard Worker    root: a Metadata instance
63*b9df5ad1SAndroid Build Coastguard Worker
64*b9df5ad1SAndroid Build Coastguard Worker  Returns:
65*b9df5ad1SAndroid Build Coastguard Worker    A list of Section/InnerNamespace instances
66*b9df5ad1SAndroid Build Coastguard Worker
67*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
68*b9df5ad1SAndroid Build Coastguard Worker    These are known as "sections" in the generated C code.
69*b9df5ad1SAndroid Build Coastguard Worker  """
70*b9df5ad1SAndroid Build Coastguard Worker  return root.find_all(_is_sec_or_ins)
71*b9df5ad1SAndroid Build Coastguard Worker
72*b9df5ad1SAndroid Build Coastguard Workerdef find_all_sections_filtered(root, visibility):
73*b9df5ad1SAndroid Build Coastguard Worker  """
74*b9df5ad1SAndroid Build Coastguard Worker  Find all descendants that are Section or InnerNamespace instances that do not
75*b9df5ad1SAndroid Build Coastguard Worker  contain entries of the supplied visibility
76*b9df5ad1SAndroid Build Coastguard Worker
77*b9df5ad1SAndroid Build Coastguard Worker  Args:
78*b9df5ad1SAndroid Build Coastguard Worker    root: a Metadata instance
79*b9df5ad1SAndroid Build Coastguard Worker    visibilities: An iterable of visibilities to filter against
80*b9df5ad1SAndroid Build Coastguard Worker
81*b9df5ad1SAndroid Build Coastguard Worker  Returns:
82*b9df5ad1SAndroid Build Coastguard Worker    A list of Section/InnerNamespace instances
83*b9df5ad1SAndroid Build Coastguard Worker
84*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
85*b9df5ad1SAndroid Build Coastguard Worker    These are known as "sections" in the generated C code.
86*b9df5ad1SAndroid Build Coastguard Worker  """
87*b9df5ad1SAndroid Build Coastguard Worker  sections = root.find_all(_is_sec_or_ins)
88*b9df5ad1SAndroid Build Coastguard Worker
89*b9df5ad1SAndroid Build Coastguard Worker  filtered_sections = []
90*b9df5ad1SAndroid Build Coastguard Worker  for sec in sections:
91*b9df5ad1SAndroid Build Coastguard Worker    if not any(filter_visibility(find_unique_entries(sec), visibility)):
92*b9df5ad1SAndroid Build Coastguard Worker      filtered_sections.append(sec)
93*b9df5ad1SAndroid Build Coastguard Worker
94*b9df5ad1SAndroid Build Coastguard Worker  return filtered_sections
95*b9df5ad1SAndroid Build Coastguard Worker
96*b9df5ad1SAndroid Build Coastguard Worker
97*b9df5ad1SAndroid Build Coastguard Workerdef find_parent_section(entry):
98*b9df5ad1SAndroid Build Coastguard Worker  """
99*b9df5ad1SAndroid Build Coastguard Worker  Find the closest ancestor that is either a Section or InnerNamespace.
100*b9df5ad1SAndroid Build Coastguard Worker
101*b9df5ad1SAndroid Build Coastguard Worker  Args:
102*b9df5ad1SAndroid Build Coastguard Worker    entry: an Entry or Clone node
103*b9df5ad1SAndroid Build Coastguard Worker
104*b9df5ad1SAndroid Build Coastguard Worker  Returns:
105*b9df5ad1SAndroid Build Coastguard Worker    An instance of Section or InnerNamespace
106*b9df5ad1SAndroid Build Coastguard Worker  """
107*b9df5ad1SAndroid Build Coastguard Worker  return entry.find_parent_first(_is_sec_or_ins)
108*b9df5ad1SAndroid Build Coastguard Worker
109*b9df5ad1SAndroid Build Coastguard Worker# find uniquely named entries (w/o recursing through inner namespaces)
110*b9df5ad1SAndroid Build Coastguard Workerdef find_unique_entries(node):
111*b9df5ad1SAndroid Build Coastguard Worker  """
112*b9df5ad1SAndroid Build Coastguard Worker  Find all uniquely named entries, without recursing through inner namespaces.
113*b9df5ad1SAndroid Build Coastguard Worker
114*b9df5ad1SAndroid Build Coastguard Worker  Args:
115*b9df5ad1SAndroid Build Coastguard Worker    node: a Section or InnerNamespace instance
116*b9df5ad1SAndroid Build Coastguard Worker
117*b9df5ad1SAndroid Build Coastguard Worker  Yields:
118*b9df5ad1SAndroid Build Coastguard Worker    A sequence of MergedEntry nodes representing an entry
119*b9df5ad1SAndroid Build Coastguard Worker
120*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
121*b9df5ad1SAndroid Build Coastguard Worker    This collapses multiple entries with the same fully qualified name into
122*b9df5ad1SAndroid Build Coastguard Worker    one entry (e.g. if there are multiple entries in different kinds).
123*b9df5ad1SAndroid Build Coastguard Worker  """
124*b9df5ad1SAndroid Build Coastguard Worker  if not isinstance(node, metadata_model.Section) and    \
125*b9df5ad1SAndroid Build Coastguard Worker     not isinstance(node, metadata_model.InnerNamespace):
126*b9df5ad1SAndroid Build Coastguard Worker      raise TypeError("expected node to be a Section or InnerNamespace")
127*b9df5ad1SAndroid Build Coastguard Worker
128*b9df5ad1SAndroid Build Coastguard Worker  d = OrderedDict()
129*b9df5ad1SAndroid Build Coastguard Worker  # remove the 'kinds' from the path between sec and the closest entries
130*b9df5ad1SAndroid Build Coastguard Worker  # then search the immediate children of the search path
131*b9df5ad1SAndroid Build Coastguard Worker  search_path = isinstance(node, metadata_model.Section) and node.kinds \
132*b9df5ad1SAndroid Build Coastguard Worker                or [node]
133*b9df5ad1SAndroid Build Coastguard Worker  for i in search_path:
134*b9df5ad1SAndroid Build Coastguard Worker      for entry in i.entries:
135*b9df5ad1SAndroid Build Coastguard Worker          d[entry.name] = entry
136*b9df5ad1SAndroid Build Coastguard Worker
137*b9df5ad1SAndroid Build Coastguard Worker  for k,v in d.items():
138*b9df5ad1SAndroid Build Coastguard Worker      yield v.merge()
139*b9df5ad1SAndroid Build Coastguard Worker
140*b9df5ad1SAndroid Build Coastguard Workerdef path_name(node):
141*b9df5ad1SAndroid Build Coastguard Worker  """
142*b9df5ad1SAndroid Build Coastguard Worker  Calculate a period-separated string path from the root to this element,
143*b9df5ad1SAndroid Build Coastguard Worker  by joining the names of each node and excluding the Metadata/Kind nodes
144*b9df5ad1SAndroid Build Coastguard Worker  from the path.
145*b9df5ad1SAndroid Build Coastguard Worker
146*b9df5ad1SAndroid Build Coastguard Worker  Args:
147*b9df5ad1SAndroid Build Coastguard Worker    node: a Node instance
148*b9df5ad1SAndroid Build Coastguard Worker
149*b9df5ad1SAndroid Build Coastguard Worker  Returns:
150*b9df5ad1SAndroid Build Coastguard Worker    A string path
151*b9df5ad1SAndroid Build Coastguard Worker  """
152*b9df5ad1SAndroid Build Coastguard Worker
153*b9df5ad1SAndroid Build Coastguard Worker  isa = lambda x,y: isinstance(x, y)
154*b9df5ad1SAndroid Build Coastguard Worker  fltr = lambda x: not isa(x, metadata_model.Metadata) and \
155*b9df5ad1SAndroid Build Coastguard Worker                   not isa(x, metadata_model.Kind)
156*b9df5ad1SAndroid Build Coastguard Worker
157*b9df5ad1SAndroid Build Coastguard Worker  path = node.find_parents(fltr)
158*b9df5ad1SAndroid Build Coastguard Worker  path = list(path)
159*b9df5ad1SAndroid Build Coastguard Worker  path.reverse()
160*b9df5ad1SAndroid Build Coastguard Worker  path.append(node)
161*b9df5ad1SAndroid Build Coastguard Worker
162*b9df5ad1SAndroid Build Coastguard Worker  return ".".join((i.name for i in path))
163*b9df5ad1SAndroid Build Coastguard Worker
164*b9df5ad1SAndroid Build Coastguard Workerdef ndk(name):
165*b9df5ad1SAndroid Build Coastguard Worker  """
166*b9df5ad1SAndroid Build Coastguard Worker  Return the NDK version of given name, which replace
167*b9df5ad1SAndroid Build Coastguard Worker  the leading "android" to "acamera"
168*b9df5ad1SAndroid Build Coastguard Worker
169*b9df5ad1SAndroid Build Coastguard Worker  Args:
170*b9df5ad1SAndroid Build Coastguard Worker    name: name string of an entry
171*b9df5ad1SAndroid Build Coastguard Worker
172*b9df5ad1SAndroid Build Coastguard Worker  Returns:
173*b9df5ad1SAndroid Build Coastguard Worker    A NDK version name string of the input name
174*b9df5ad1SAndroid Build Coastguard Worker  """
175*b9df5ad1SAndroid Build Coastguard Worker  name_list = name.split(".")
176*b9df5ad1SAndroid Build Coastguard Worker  if name_list[0] == "android":
177*b9df5ad1SAndroid Build Coastguard Worker    name_list[0] = "acamera"
178*b9df5ad1SAndroid Build Coastguard Worker  return ".".join(name_list)
179*b9df5ad1SAndroid Build Coastguard Worker
180*b9df5ad1SAndroid Build Coastguard Workerdef protobuf_type(entry):
181*b9df5ad1SAndroid Build Coastguard Worker  """
182*b9df5ad1SAndroid Build Coastguard Worker  Return the protocol buffer message type for input metadata entry.
183*b9df5ad1SAndroid Build Coastguard Worker  Only support types used by static metadata right now
184*b9df5ad1SAndroid Build Coastguard Worker
185*b9df5ad1SAndroid Build Coastguard Worker  Returns:
186*b9df5ad1SAndroid Build Coastguard Worker    A string of protocol buffer type. Ex: "optional int32" or "repeated RangeInt"
187*b9df5ad1SAndroid Build Coastguard Worker  """
188*b9df5ad1SAndroid Build Coastguard Worker  typeName = None
189*b9df5ad1SAndroid Build Coastguard Worker  if entry.typedef is None:
190*b9df5ad1SAndroid Build Coastguard Worker    typeName = entry.type
191*b9df5ad1SAndroid Build Coastguard Worker  else:
192*b9df5ad1SAndroid Build Coastguard Worker    typeName = entry.typedef.name
193*b9df5ad1SAndroid Build Coastguard Worker
194*b9df5ad1SAndroid Build Coastguard Worker  typename_to_protobuftype = {
195*b9df5ad1SAndroid Build Coastguard Worker    "rational"               : "Rational",
196*b9df5ad1SAndroid Build Coastguard Worker    "size"                   : "Size",
197*b9df5ad1SAndroid Build Coastguard Worker    "sizeF"                  : "SizeF",
198*b9df5ad1SAndroid Build Coastguard Worker    "rectangle"              : "Rect",
199*b9df5ad1SAndroid Build Coastguard Worker    "streamConfigurationMap" : "StreamConfigurations",
200*b9df5ad1SAndroid Build Coastguard Worker    "mandatoryStreamCombination" : "MandatoryStreamCombination",
201*b9df5ad1SAndroid Build Coastguard Worker    "rangeInt"               : "RangeInt",
202*b9df5ad1SAndroid Build Coastguard Worker    "rangeLong"              : "RangeLong",
203*b9df5ad1SAndroid Build Coastguard Worker    "rangeFloat"             : "RangeFloat",
204*b9df5ad1SAndroid Build Coastguard Worker    "colorSpaceTransform"    : "ColorSpaceTransform",
205*b9df5ad1SAndroid Build Coastguard Worker    "blackLevelPattern"      : "BlackLevelPattern",
206*b9df5ad1SAndroid Build Coastguard Worker    "byte"                   : "int32", # protocol buffer don't support byte
207*b9df5ad1SAndroid Build Coastguard Worker    "boolean"                : "bool",
208*b9df5ad1SAndroid Build Coastguard Worker    "float"                  : "float",
209*b9df5ad1SAndroid Build Coastguard Worker    "double"                 : "double",
210*b9df5ad1SAndroid Build Coastguard Worker    "int32"                  : "int32",
211*b9df5ad1SAndroid Build Coastguard Worker    "int64"                  : "int64",
212*b9df5ad1SAndroid Build Coastguard Worker    "enumList"               : "int32",
213*b9df5ad1SAndroid Build Coastguard Worker    "string"                 : "string",
214*b9df5ad1SAndroid Build Coastguard Worker    "capability"             : "Capability",
215*b9df5ad1SAndroid Build Coastguard Worker    "multiResolutionStreamConfigurationMap" : "MultiResolutionStreamConfigurations",
216*b9df5ad1SAndroid Build Coastguard Worker    "deviceStateSensorOrientationMap"  : "DeviceStateSensorOrientationMap",
217*b9df5ad1SAndroid Build Coastguard Worker    "dynamicRangeProfiles"   : "DynamicRangeProfiles",
218*b9df5ad1SAndroid Build Coastguard Worker    "colorSpaceProfiles"     : "ColorSpaceProfiles",
219*b9df5ad1SAndroid Build Coastguard Worker    "versionCode"            : "int32",
220*b9df5ad1SAndroid Build Coastguard Worker    "sharedSessionConfiguration"  : "SharedSessionConfiguration",
221*b9df5ad1SAndroid Build Coastguard Worker  }
222*b9df5ad1SAndroid Build Coastguard Worker
223*b9df5ad1SAndroid Build Coastguard Worker  if typeName not in typename_to_protobuftype:
224*b9df5ad1SAndroid Build Coastguard Worker    print("  ERROR: Could not find protocol buffer type for {%s} type {%s} typedef {%s}" % \
225*b9df5ad1SAndroid Build Coastguard Worker          (entry.name, entry.type, entry.typedef), file=sys.stderr)
226*b9df5ad1SAndroid Build Coastguard Worker
227*b9df5ad1SAndroid Build Coastguard Worker  proto_type = typename_to_protobuftype[typeName]
228*b9df5ad1SAndroid Build Coastguard Worker
229*b9df5ad1SAndroid Build Coastguard Worker  prefix = "optional"
230*b9df5ad1SAndroid Build Coastguard Worker  if entry.container == 'array':
231*b9df5ad1SAndroid Build Coastguard Worker    has_variable_size = False
232*b9df5ad1SAndroid Build Coastguard Worker    for size in entry.container_sizes:
233*b9df5ad1SAndroid Build Coastguard Worker      try:
234*b9df5ad1SAndroid Build Coastguard Worker        size_int = int(size)
235*b9df5ad1SAndroid Build Coastguard Worker      except ValueError:
236*b9df5ad1SAndroid Build Coastguard Worker        has_variable_size = True
237*b9df5ad1SAndroid Build Coastguard Worker
238*b9df5ad1SAndroid Build Coastguard Worker    if has_variable_size:
239*b9df5ad1SAndroid Build Coastguard Worker      prefix = "repeated"
240*b9df5ad1SAndroid Build Coastguard Worker
241*b9df5ad1SAndroid Build Coastguard Worker  return "%s %s" %(prefix, proto_type)
242*b9df5ad1SAndroid Build Coastguard Worker
243*b9df5ad1SAndroid Build Coastguard Worker
244*b9df5ad1SAndroid Build Coastguard Workerdef protobuf_name(entry):
245*b9df5ad1SAndroid Build Coastguard Worker  """
246*b9df5ad1SAndroid Build Coastguard Worker  Return the protocol buffer field name for input metadata entry
247*b9df5ad1SAndroid Build Coastguard Worker
248*b9df5ad1SAndroid Build Coastguard Worker  Returns:
249*b9df5ad1SAndroid Build Coastguard Worker    A string. Ex: "android_colorCorrection_availableAberrationModes"
250*b9df5ad1SAndroid Build Coastguard Worker  """
251*b9df5ad1SAndroid Build Coastguard Worker  return entry.name.replace(".", "_")
252*b9df5ad1SAndroid Build Coastguard Worker
253*b9df5ad1SAndroid Build Coastguard Workerdef has_descendants_with_enums(node):
254*b9df5ad1SAndroid Build Coastguard Worker  """
255*b9df5ad1SAndroid Build Coastguard Worker  Determine whether or not the current node is or has any descendants with an
256*b9df5ad1SAndroid Build Coastguard Worker  Enum node.
257*b9df5ad1SAndroid Build Coastguard Worker
258*b9df5ad1SAndroid Build Coastguard Worker  Args:
259*b9df5ad1SAndroid Build Coastguard Worker    node: a Node instance
260*b9df5ad1SAndroid Build Coastguard Worker
261*b9df5ad1SAndroid Build Coastguard Worker  Returns:
262*b9df5ad1SAndroid Build Coastguard Worker    True if it finds an Enum node in the subtree, False otherwise
263*b9df5ad1SAndroid Build Coastguard Worker  """
264*b9df5ad1SAndroid Build Coastguard Worker  return bool(node.find_first(lambda x: isinstance(x, metadata_model.Enum)))
265*b9df5ad1SAndroid Build Coastguard Worker
266*b9df5ad1SAndroid Build Coastguard Workerdef get_children_by_throwing_away_kind(node, member='entries'):
267*b9df5ad1SAndroid Build Coastguard Worker  """
268*b9df5ad1SAndroid Build Coastguard Worker  Get the children of this node by compressing the subtree together by removing
269*b9df5ad1SAndroid Build Coastguard Worker  the kind and then combining any children nodes with the same name together.
270*b9df5ad1SAndroid Build Coastguard Worker
271*b9df5ad1SAndroid Build Coastguard Worker  Args:
272*b9df5ad1SAndroid Build Coastguard Worker    node: An instance of Section, InnerNamespace, or Kind
273*b9df5ad1SAndroid Build Coastguard Worker
274*b9df5ad1SAndroid Build Coastguard Worker  Returns:
275*b9df5ad1SAndroid Build Coastguard Worker    An iterable over the combined children of the subtree of node,
276*b9df5ad1SAndroid Build Coastguard Worker    as if the Kinds never existed.
277*b9df5ad1SAndroid Build Coastguard Worker
278*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
279*b9df5ad1SAndroid Build Coastguard Worker    Not recursive. Call this function repeatedly on each child.
280*b9df5ad1SAndroid Build Coastguard Worker  """
281*b9df5ad1SAndroid Build Coastguard Worker
282*b9df5ad1SAndroid Build Coastguard Worker  if isinstance(node, metadata_model.Section):
283*b9df5ad1SAndroid Build Coastguard Worker    # Note that this makes jump from Section to Kind,
284*b9df5ad1SAndroid Build Coastguard Worker    # skipping the Kind entirely in the tree.
285*b9df5ad1SAndroid Build Coastguard Worker    node_to_combine = node.combine_kinds_into_single_node()
286*b9df5ad1SAndroid Build Coastguard Worker  else:
287*b9df5ad1SAndroid Build Coastguard Worker    node_to_combine = node
288*b9df5ad1SAndroid Build Coastguard Worker
289*b9df5ad1SAndroid Build Coastguard Worker  combined_kind = node_to_combine.combine_children_by_name()
290*b9df5ad1SAndroid Build Coastguard Worker
291*b9df5ad1SAndroid Build Coastguard Worker  return (i for i in getattr(combined_kind, member))
292*b9df5ad1SAndroid Build Coastguard Worker
293*b9df5ad1SAndroid Build Coastguard Workerdef get_children_by_filtering_kind(section, kind_name, member='entries'):
294*b9df5ad1SAndroid Build Coastguard Worker  """
295*b9df5ad1SAndroid Build Coastguard Worker  Takes a section and yields the children of the merged kind under this section.
296*b9df5ad1SAndroid Build Coastguard Worker
297*b9df5ad1SAndroid Build Coastguard Worker  Args:
298*b9df5ad1SAndroid Build Coastguard Worker    section: An instance of Section
299*b9df5ad1SAndroid Build Coastguard Worker    kind_name: A name of the kind, i.e. 'dynamic' or 'static' or 'controls'
300*b9df5ad1SAndroid Build Coastguard Worker
301*b9df5ad1SAndroid Build Coastguard Worker  Returns:
302*b9df5ad1SAndroid Build Coastguard Worker    An iterable over the children of the specified merged kind.
303*b9df5ad1SAndroid Build Coastguard Worker  """
304*b9df5ad1SAndroid Build Coastguard Worker
305*b9df5ad1SAndroid Build Coastguard Worker  matched_kind = next((i for i in section.merged_kinds if i.name == kind_name), None)
306*b9df5ad1SAndroid Build Coastguard Worker
307*b9df5ad1SAndroid Build Coastguard Worker  if matched_kind:
308*b9df5ad1SAndroid Build Coastguard Worker    return getattr(matched_kind, member)
309*b9df5ad1SAndroid Build Coastguard Worker  else:
310*b9df5ad1SAndroid Build Coastguard Worker    return ()
311*b9df5ad1SAndroid Build Coastguard Worker
312*b9df5ad1SAndroid Build Coastguard Worker##
313*b9df5ad1SAndroid Build Coastguard Worker## Filters
314*b9df5ad1SAndroid Build Coastguard Worker##
315*b9df5ad1SAndroid Build Coastguard Worker
316*b9df5ad1SAndroid Build Coastguard Worker# abcDef.xyz -> ABC_DEF_XYZ
317*b9df5ad1SAndroid Build Coastguard Workerdef csym(name):
318*b9df5ad1SAndroid Build Coastguard Worker  """
319*b9df5ad1SAndroid Build Coastguard Worker  Convert an entry name string into an uppercase C symbol.
320*b9df5ad1SAndroid Build Coastguard Worker
321*b9df5ad1SAndroid Build Coastguard Worker  Returns:
322*b9df5ad1SAndroid Build Coastguard Worker    A string
323*b9df5ad1SAndroid Build Coastguard Worker
324*b9df5ad1SAndroid Build Coastguard Worker  Example:
325*b9df5ad1SAndroid Build Coastguard Worker    csym('abcDef.xyz') == 'ABC_DEF_XYZ'
326*b9df5ad1SAndroid Build Coastguard Worker  """
327*b9df5ad1SAndroid Build Coastguard Worker  newstr = name
328*b9df5ad1SAndroid Build Coastguard Worker  newstr = "".join([i.isupper() and ("_" + i) or i for i in newstr]).upper()
329*b9df5ad1SAndroid Build Coastguard Worker  newstr = newstr.replace(".", "_")
330*b9df5ad1SAndroid Build Coastguard Worker  return newstr
331*b9df5ad1SAndroid Build Coastguard Worker
332*b9df5ad1SAndroid Build Coastguard Worker# abcDef.xyz -> abc_def_xyz
333*b9df5ad1SAndroid Build Coastguard Workerdef csyml(name):
334*b9df5ad1SAndroid Build Coastguard Worker  """
335*b9df5ad1SAndroid Build Coastguard Worker  Convert an entry name string into a lowercase C symbol.
336*b9df5ad1SAndroid Build Coastguard Worker
337*b9df5ad1SAndroid Build Coastguard Worker  Returns:
338*b9df5ad1SAndroid Build Coastguard Worker    A string
339*b9df5ad1SAndroid Build Coastguard Worker
340*b9df5ad1SAndroid Build Coastguard Worker  Example:
341*b9df5ad1SAndroid Build Coastguard Worker    csyml('abcDef.xyz') == 'abc_def_xyz'
342*b9df5ad1SAndroid Build Coastguard Worker  """
343*b9df5ad1SAndroid Build Coastguard Worker  return csym(name).lower()
344*b9df5ad1SAndroid Build Coastguard Worker
345*b9df5ad1SAndroid Build Coastguard Worker# pad with spaces to make string len == size. add new line if too big
346*b9df5ad1SAndroid Build Coastguard Workerdef ljust(size, indent=4):
347*b9df5ad1SAndroid Build Coastguard Worker  """
348*b9df5ad1SAndroid Build Coastguard Worker  Creates a function that given a string will pad it with spaces to make
349*b9df5ad1SAndroid Build Coastguard Worker  the string length == size. Adds a new line if the string was too big.
350*b9df5ad1SAndroid Build Coastguard Worker
351*b9df5ad1SAndroid Build Coastguard Worker  Args:
352*b9df5ad1SAndroid Build Coastguard Worker    size: an integer representing how much spacing should be added
353*b9df5ad1SAndroid Build Coastguard Worker    indent: an integer representing the initial indendation level
354*b9df5ad1SAndroid Build Coastguard Worker
355*b9df5ad1SAndroid Build Coastguard Worker  Returns:
356*b9df5ad1SAndroid Build Coastguard Worker    A function that takes a string and returns a string.
357*b9df5ad1SAndroid Build Coastguard Worker
358*b9df5ad1SAndroid Build Coastguard Worker  Example:
359*b9df5ad1SAndroid Build Coastguard Worker    ljust(8)("hello") == 'hello   '
360*b9df5ad1SAndroid Build Coastguard Worker
361*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
362*b9df5ad1SAndroid Build Coastguard Worker    Deprecated. Use pad instead since it works for non-first items in a
363*b9df5ad1SAndroid Build Coastguard Worker    Mako template.
364*b9df5ad1SAndroid Build Coastguard Worker  """
365*b9df5ad1SAndroid Build Coastguard Worker  def inner(what):
366*b9df5ad1SAndroid Build Coastguard Worker    newstr = what.ljust(size)
367*b9df5ad1SAndroid Build Coastguard Worker    if len(newstr) > size:
368*b9df5ad1SAndroid Build Coastguard Worker      return what + "\n" + "".ljust(indent + size)
369*b9df5ad1SAndroid Build Coastguard Worker    else:
370*b9df5ad1SAndroid Build Coastguard Worker      return newstr
371*b9df5ad1SAndroid Build Coastguard Worker  return inner
372*b9df5ad1SAndroid Build Coastguard Worker
373*b9df5ad1SAndroid Build Coastguard Workerdef _find_new_line():
374*b9df5ad1SAndroid Build Coastguard Worker
375*b9df5ad1SAndroid Build Coastguard Worker  if _context_buf is None:
376*b9df5ad1SAndroid Build Coastguard Worker    raise ValueError("Context buffer was not set")
377*b9df5ad1SAndroid Build Coastguard Worker
378*b9df5ad1SAndroid Build Coastguard Worker  buf = _context_buf
379*b9df5ad1SAndroid Build Coastguard Worker  x = -1 # since the first read is always ''
380*b9df5ad1SAndroid Build Coastguard Worker  cur_pos = buf.tell()
381*b9df5ad1SAndroid Build Coastguard Worker  while buf.tell() > 0 and buf.read(1) != '\n':
382*b9df5ad1SAndroid Build Coastguard Worker    buf.seek(cur_pos - x)
383*b9df5ad1SAndroid Build Coastguard Worker    x = x + 1
384*b9df5ad1SAndroid Build Coastguard Worker
385*b9df5ad1SAndroid Build Coastguard Worker  buf.seek(cur_pos)
386*b9df5ad1SAndroid Build Coastguard Worker
387*b9df5ad1SAndroid Build Coastguard Worker  return int(x)
388*b9df5ad1SAndroid Build Coastguard Worker
389*b9df5ad1SAndroid Build Coastguard Worker# Pad the string until the buffer reaches the desired column.
390*b9df5ad1SAndroid Build Coastguard Worker# If string is too long, insert a new line with 'col' spaces instead
391*b9df5ad1SAndroid Build Coastguard Workerdef pad(col):
392*b9df5ad1SAndroid Build Coastguard Worker  """
393*b9df5ad1SAndroid Build Coastguard Worker  Create a function that given a string will pad it to the specified column col.
394*b9df5ad1SAndroid Build Coastguard Worker  If the string overflows the column, put the string on a new line and pad it.
395*b9df5ad1SAndroid Build Coastguard Worker
396*b9df5ad1SAndroid Build Coastguard Worker  Args:
397*b9df5ad1SAndroid Build Coastguard Worker    col: an integer specifying the column number
398*b9df5ad1SAndroid Build Coastguard Worker
399*b9df5ad1SAndroid Build Coastguard Worker  Returns:
400*b9df5ad1SAndroid Build Coastguard Worker    A function that given a string will produce a padded string.
401*b9df5ad1SAndroid Build Coastguard Worker
402*b9df5ad1SAndroid Build Coastguard Worker  Example:
403*b9df5ad1SAndroid Build Coastguard Worker    pad(8)("hello") == 'hello   '
404*b9df5ad1SAndroid Build Coastguard Worker
405*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
406*b9df5ad1SAndroid Build Coastguard Worker    This keeps track of the line written by Mako so far, so it will always
407*b9df5ad1SAndroid Build Coastguard Worker    align to the column number correctly.
408*b9df5ad1SAndroid Build Coastguard Worker  """
409*b9df5ad1SAndroid Build Coastguard Worker  def inner(what):
410*b9df5ad1SAndroid Build Coastguard Worker    wut = int(col)
411*b9df5ad1SAndroid Build Coastguard Worker    current_col = _find_new_line()
412*b9df5ad1SAndroid Build Coastguard Worker
413*b9df5ad1SAndroid Build Coastguard Worker    if len(what) > wut - current_col:
414*b9df5ad1SAndroid Build Coastguard Worker      return what + "\n".ljust(col)
415*b9df5ad1SAndroid Build Coastguard Worker    else:
416*b9df5ad1SAndroid Build Coastguard Worker      return what.ljust(wut - current_col)
417*b9df5ad1SAndroid Build Coastguard Worker  return inner
418*b9df5ad1SAndroid Build Coastguard Worker
419*b9df5ad1SAndroid Build Coastguard Worker# int32 -> TYPE_INT32, byte -> TYPE_BYTE, etc. note that enum -> TYPE_INT32
420*b9df5ad1SAndroid Build Coastguard Workerdef ctype_enum(what):
421*b9df5ad1SAndroid Build Coastguard Worker  """
422*b9df5ad1SAndroid Build Coastguard Worker  Generate a camera_metadata_type_t symbol from a type string.
423*b9df5ad1SAndroid Build Coastguard Worker
424*b9df5ad1SAndroid Build Coastguard Worker  Args:
425*b9df5ad1SAndroid Build Coastguard Worker    what: a type string
426*b9df5ad1SAndroid Build Coastguard Worker
427*b9df5ad1SAndroid Build Coastguard Worker  Returns:
428*b9df5ad1SAndroid Build Coastguard Worker    A string representing the camera_metadata_type_t
429*b9df5ad1SAndroid Build Coastguard Worker
430*b9df5ad1SAndroid Build Coastguard Worker  Example:
431*b9df5ad1SAndroid Build Coastguard Worker    ctype_enum('int32') == 'TYPE_INT32'
432*b9df5ad1SAndroid Build Coastguard Worker    ctype_enum('int64') == 'TYPE_INT64'
433*b9df5ad1SAndroid Build Coastguard Worker    ctype_enum('float') == 'TYPE_FLOAT'
434*b9df5ad1SAndroid Build Coastguard Worker
435*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
436*b9df5ad1SAndroid Build Coastguard Worker    An enum is coerced to a byte since the rest of the camera_metadata
437*b9df5ad1SAndroid Build Coastguard Worker    code doesn't support enums directly yet.
438*b9df5ad1SAndroid Build Coastguard Worker  """
439*b9df5ad1SAndroid Build Coastguard Worker  return 'TYPE_%s' %(what.upper())
440*b9df5ad1SAndroid Build Coastguard Worker
441*b9df5ad1SAndroid Build Coastguard Worker
442*b9df5ad1SAndroid Build Coastguard Worker# Calculate a java type name from an entry with a Typedef node
443*b9df5ad1SAndroid Build Coastguard Workerdef _jtypedef_type(entry):
444*b9df5ad1SAndroid Build Coastguard Worker  typedef = entry.typedef
445*b9df5ad1SAndroid Build Coastguard Worker  additional = ''
446*b9df5ad1SAndroid Build Coastguard Worker
447*b9df5ad1SAndroid Build Coastguard Worker  # Hacky way to deal with arrays. Assume that if we have
448*b9df5ad1SAndroid Build Coastguard Worker  # size 'Constant x N' the Constant is part of the Typedef size.
449*b9df5ad1SAndroid Build Coastguard Worker  # So something sized just 'Constant', 'Constant1 x Constant2', etc
450*b9df5ad1SAndroid Build Coastguard Worker  # is not treated as a real java array.
451*b9df5ad1SAndroid Build Coastguard Worker  if entry.container == 'array':
452*b9df5ad1SAndroid Build Coastguard Worker    has_variable_size = False
453*b9df5ad1SAndroid Build Coastguard Worker    for size in entry.container_sizes:
454*b9df5ad1SAndroid Build Coastguard Worker      try:
455*b9df5ad1SAndroid Build Coastguard Worker        size_int = int(size)
456*b9df5ad1SAndroid Build Coastguard Worker      except ValueError:
457*b9df5ad1SAndroid Build Coastguard Worker        has_variable_size = True
458*b9df5ad1SAndroid Build Coastguard Worker
459*b9df5ad1SAndroid Build Coastguard Worker    if has_variable_size:
460*b9df5ad1SAndroid Build Coastguard Worker      additional = '[]'
461*b9df5ad1SAndroid Build Coastguard Worker
462*b9df5ad1SAndroid Build Coastguard Worker  try:
463*b9df5ad1SAndroid Build Coastguard Worker    name = typedef.languages['java']
464*b9df5ad1SAndroid Build Coastguard Worker
465*b9df5ad1SAndroid Build Coastguard Worker    return "%s%s" %(name, additional)
466*b9df5ad1SAndroid Build Coastguard Worker  except KeyError:
467*b9df5ad1SAndroid Build Coastguard Worker    return None
468*b9df5ad1SAndroid Build Coastguard Worker
469*b9df5ad1SAndroid Build Coastguard Worker# Box if primitive. Otherwise leave unboxed.
470*b9df5ad1SAndroid Build Coastguard Workerdef _jtype_box(type_name):
471*b9df5ad1SAndroid Build Coastguard Worker  mapping = {
472*b9df5ad1SAndroid Build Coastguard Worker    'boolean': 'Boolean',
473*b9df5ad1SAndroid Build Coastguard Worker    'byte': 'Byte',
474*b9df5ad1SAndroid Build Coastguard Worker    'int': 'Integer',
475*b9df5ad1SAndroid Build Coastguard Worker    'float': 'Float',
476*b9df5ad1SAndroid Build Coastguard Worker    'double': 'Double',
477*b9df5ad1SAndroid Build Coastguard Worker    'long': 'Long'
478*b9df5ad1SAndroid Build Coastguard Worker  }
479*b9df5ad1SAndroid Build Coastguard Worker
480*b9df5ad1SAndroid Build Coastguard Worker  return mapping.get(type_name, type_name)
481*b9df5ad1SAndroid Build Coastguard Worker
482*b9df5ad1SAndroid Build Coastguard Workerdef jtype_unboxed(entry):
483*b9df5ad1SAndroid Build Coastguard Worker  """
484*b9df5ad1SAndroid Build Coastguard Worker  Calculate the Java type from an entry type string, to be used whenever we
485*b9df5ad1SAndroid Build Coastguard Worker  need the regular type in Java. It's not boxed, so it can't be used as a
486*b9df5ad1SAndroid Build Coastguard Worker  generic type argument when the entry type happens to resolve to a primitive.
487*b9df5ad1SAndroid Build Coastguard Worker
488*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
489*b9df5ad1SAndroid Build Coastguard Worker    Since Java generics cannot be instantiated with primitives, this version
490*b9df5ad1SAndroid Build Coastguard Worker    is not applicable in that case. Use jtype_boxed instead for that.
491*b9df5ad1SAndroid Build Coastguard Worker
492*b9df5ad1SAndroid Build Coastguard Worker  Returns:
493*b9df5ad1SAndroid Build Coastguard Worker    The string representing the Java type.
494*b9df5ad1SAndroid Build Coastguard Worker  """
495*b9df5ad1SAndroid Build Coastguard Worker  if not isinstance(entry, metadata_model.Entry):
496*b9df5ad1SAndroid Build Coastguard Worker    raise ValueError("Expected entry to be an instance of Entry")
497*b9df5ad1SAndroid Build Coastguard Worker
498*b9df5ad1SAndroid Build Coastguard Worker  metadata_type = entry.type
499*b9df5ad1SAndroid Build Coastguard Worker
500*b9df5ad1SAndroid Build Coastguard Worker  java_type = None
501*b9df5ad1SAndroid Build Coastguard Worker
502*b9df5ad1SAndroid Build Coastguard Worker  if entry.typedef:
503*b9df5ad1SAndroid Build Coastguard Worker    typedef_name = _jtypedef_type(entry)
504*b9df5ad1SAndroid Build Coastguard Worker    if typedef_name:
505*b9df5ad1SAndroid Build Coastguard Worker      java_type = typedef_name # already takes into account arrays
506*b9df5ad1SAndroid Build Coastguard Worker
507*b9df5ad1SAndroid Build Coastguard Worker  if not java_type:
508*b9df5ad1SAndroid Build Coastguard Worker    if not java_type and entry.enum and metadata_type == 'byte':
509*b9df5ad1SAndroid Build Coastguard Worker      # Always map byte enums to Java ints, unless there's a typedef override
510*b9df5ad1SAndroid Build Coastguard Worker      base_type = 'int'
511*b9df5ad1SAndroid Build Coastguard Worker
512*b9df5ad1SAndroid Build Coastguard Worker    else:
513*b9df5ad1SAndroid Build Coastguard Worker      mapping = {
514*b9df5ad1SAndroid Build Coastguard Worker        'int32': 'int',
515*b9df5ad1SAndroid Build Coastguard Worker        'int64': 'long',
516*b9df5ad1SAndroid Build Coastguard Worker        'float': 'float',
517*b9df5ad1SAndroid Build Coastguard Worker        'double': 'double',
518*b9df5ad1SAndroid Build Coastguard Worker        'byte': 'byte',
519*b9df5ad1SAndroid Build Coastguard Worker        'rational': 'Rational'
520*b9df5ad1SAndroid Build Coastguard Worker      }
521*b9df5ad1SAndroid Build Coastguard Worker
522*b9df5ad1SAndroid Build Coastguard Worker      base_type = mapping[metadata_type]
523*b9df5ad1SAndroid Build Coastguard Worker
524*b9df5ad1SAndroid Build Coastguard Worker    # Convert to array (enums, basic types)
525*b9df5ad1SAndroid Build Coastguard Worker    if entry.container == 'array':
526*b9df5ad1SAndroid Build Coastguard Worker      additional = '[]'
527*b9df5ad1SAndroid Build Coastguard Worker    else:
528*b9df5ad1SAndroid Build Coastguard Worker      additional = ''
529*b9df5ad1SAndroid Build Coastguard Worker
530*b9df5ad1SAndroid Build Coastguard Worker    java_type = '%s%s' %(base_type, additional)
531*b9df5ad1SAndroid Build Coastguard Worker
532*b9df5ad1SAndroid Build Coastguard Worker  # Now box this sucker.
533*b9df5ad1SAndroid Build Coastguard Worker  return java_type
534*b9df5ad1SAndroid Build Coastguard Worker
535*b9df5ad1SAndroid Build Coastguard Workerdef jtype_boxed(entry):
536*b9df5ad1SAndroid Build Coastguard Worker  """
537*b9df5ad1SAndroid Build Coastguard Worker  Calculate the Java type from an entry type string, to be used as a generic
538*b9df5ad1SAndroid Build Coastguard Worker  type argument in Java. The type is guaranteed to inherit from Object.
539*b9df5ad1SAndroid Build Coastguard Worker
540*b9df5ad1SAndroid Build Coastguard Worker  It will only box when absolutely necessary, i.e. int -> Integer[], but
541*b9df5ad1SAndroid Build Coastguard Worker  int[] -> int[].
542*b9df5ad1SAndroid Build Coastguard Worker
543*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
544*b9df5ad1SAndroid Build Coastguard Worker    Since Java generics cannot be instantiated with primitives, this version
545*b9df5ad1SAndroid Build Coastguard Worker    will use boxed types when absolutely required.
546*b9df5ad1SAndroid Build Coastguard Worker
547*b9df5ad1SAndroid Build Coastguard Worker  Returns:
548*b9df5ad1SAndroid Build Coastguard Worker    The string representing the boxed Java type.
549*b9df5ad1SAndroid Build Coastguard Worker  """
550*b9df5ad1SAndroid Build Coastguard Worker  unboxed_type = jtype_unboxed(entry)
551*b9df5ad1SAndroid Build Coastguard Worker  return _jtype_box(unboxed_type)
552*b9df5ad1SAndroid Build Coastguard Worker
553*b9df5ad1SAndroid Build Coastguard Workerdef _is_jtype_generic(entry):
554*b9df5ad1SAndroid Build Coastguard Worker  """
555*b9df5ad1SAndroid Build Coastguard Worker  Determine whether or not the Java type represented by the entry type
556*b9df5ad1SAndroid Build Coastguard Worker  string and/or typedef is a Java generic.
557*b9df5ad1SAndroid Build Coastguard Worker
558*b9df5ad1SAndroid Build Coastguard Worker  For example, "Range<Integer>" would be considered a generic, whereas
559*b9df5ad1SAndroid Build Coastguard Worker  a "MeteringRectangle" or a plain "Integer" would not be considered a generic.
560*b9df5ad1SAndroid Build Coastguard Worker
561*b9df5ad1SAndroid Build Coastguard Worker  Args:
562*b9df5ad1SAndroid Build Coastguard Worker    entry: An instance of an Entry node
563*b9df5ad1SAndroid Build Coastguard Worker
564*b9df5ad1SAndroid Build Coastguard Worker  Returns:
565*b9df5ad1SAndroid Build Coastguard Worker    True if it's a java generic, False otherwise.
566*b9df5ad1SAndroid Build Coastguard Worker  """
567*b9df5ad1SAndroid Build Coastguard Worker  if entry.typedef:
568*b9df5ad1SAndroid Build Coastguard Worker    local_typedef = _jtypedef_type(entry)
569*b9df5ad1SAndroid Build Coastguard Worker    if local_typedef:
570*b9df5ad1SAndroid Build Coastguard Worker      match = re.search(r'<.*>', local_typedef)
571*b9df5ad1SAndroid Build Coastguard Worker      return bool(match)
572*b9df5ad1SAndroid Build Coastguard Worker  return False
573*b9df5ad1SAndroid Build Coastguard Worker
574*b9df5ad1SAndroid Build Coastguard Workerdef _jtype_primitive(what):
575*b9df5ad1SAndroid Build Coastguard Worker  """
576*b9df5ad1SAndroid Build Coastguard Worker  Calculate the Java type from an entry type string.
577*b9df5ad1SAndroid Build Coastguard Worker
578*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
579*b9df5ad1SAndroid Build Coastguard Worker    Makes a special exception for Rational, since it's a primitive in terms of
580*b9df5ad1SAndroid Build Coastguard Worker    the C-library camera_metadata type system.
581*b9df5ad1SAndroid Build Coastguard Worker
582*b9df5ad1SAndroid Build Coastguard Worker  Returns:
583*b9df5ad1SAndroid Build Coastguard Worker    The string representing the primitive type
584*b9df5ad1SAndroid Build Coastguard Worker  """
585*b9df5ad1SAndroid Build Coastguard Worker  mapping = {
586*b9df5ad1SAndroid Build Coastguard Worker    'int32': 'int',
587*b9df5ad1SAndroid Build Coastguard Worker    'int64': 'long',
588*b9df5ad1SAndroid Build Coastguard Worker    'float': 'float',
589*b9df5ad1SAndroid Build Coastguard Worker    'double': 'double',
590*b9df5ad1SAndroid Build Coastguard Worker    'byte': 'byte',
591*b9df5ad1SAndroid Build Coastguard Worker    'rational': 'Rational'
592*b9df5ad1SAndroid Build Coastguard Worker  }
593*b9df5ad1SAndroid Build Coastguard Worker
594*b9df5ad1SAndroid Build Coastguard Worker  try:
595*b9df5ad1SAndroid Build Coastguard Worker    return mapping[what]
596*b9df5ad1SAndroid Build Coastguard Worker  except KeyError as e:
597*b9df5ad1SAndroid Build Coastguard Worker    raise ValueError("Can't map '%s' to a primitive, not supported" %what)
598*b9df5ad1SAndroid Build Coastguard Worker
599*b9df5ad1SAndroid Build Coastguard Workerdef jclass(entry):
600*b9df5ad1SAndroid Build Coastguard Worker  """
601*b9df5ad1SAndroid Build Coastguard Worker  Calculate the java Class reference string for an entry.
602*b9df5ad1SAndroid Build Coastguard Worker
603*b9df5ad1SAndroid Build Coastguard Worker  Args:
604*b9df5ad1SAndroid Build Coastguard Worker    entry: an Entry node
605*b9df5ad1SAndroid Build Coastguard Worker
606*b9df5ad1SAndroid Build Coastguard Worker  Example:
607*b9df5ad1SAndroid Build Coastguard Worker    <entry name="some_int" type="int32"/>
608*b9df5ad1SAndroid Build Coastguard Worker    <entry name="some_int_array" type="int32" container='array'/>
609*b9df5ad1SAndroid Build Coastguard Worker
610*b9df5ad1SAndroid Build Coastguard Worker    jclass(some_int) == 'int.class'
611*b9df5ad1SAndroid Build Coastguard Worker    jclass(some_int_array) == 'int[].class'
612*b9df5ad1SAndroid Build Coastguard Worker
613*b9df5ad1SAndroid Build Coastguard Worker  Returns:
614*b9df5ad1SAndroid Build Coastguard Worker    The ClassName.class string
615*b9df5ad1SAndroid Build Coastguard Worker  """
616*b9df5ad1SAndroid Build Coastguard Worker
617*b9df5ad1SAndroid Build Coastguard Worker  return "%s.class" %jtype_unboxed(entry)
618*b9df5ad1SAndroid Build Coastguard Worker
619*b9df5ad1SAndroid Build Coastguard Workerdef jkey_type_token(entry):
620*b9df5ad1SAndroid Build Coastguard Worker  """
621*b9df5ad1SAndroid Build Coastguard Worker  Calculate the java type token compatible with a Key constructor.
622*b9df5ad1SAndroid Build Coastguard Worker  This will be the Java Class<T> for non-generic classes, and a
623*b9df5ad1SAndroid Build Coastguard Worker  TypeReference<T> for generic classes.
624*b9df5ad1SAndroid Build Coastguard Worker
625*b9df5ad1SAndroid Build Coastguard Worker  Args:
626*b9df5ad1SAndroid Build Coastguard Worker    entry: An entry node
627*b9df5ad1SAndroid Build Coastguard Worker
628*b9df5ad1SAndroid Build Coastguard Worker  Returns:
629*b9df5ad1SAndroid Build Coastguard Worker    The ClassName.class string, or 'new TypeReference<ClassName>() {{ }}' string
630*b9df5ad1SAndroid Build Coastguard Worker  """
631*b9df5ad1SAndroid Build Coastguard Worker  if _is_jtype_generic(entry):
632*b9df5ad1SAndroid Build Coastguard Worker    return "new TypeReference<%s>() {{ }}" %(jtype_boxed(entry))
633*b9df5ad1SAndroid Build Coastguard Worker  else:
634*b9df5ad1SAndroid Build Coastguard Worker    return jclass(entry)
635*b9df5ad1SAndroid Build Coastguard Worker
636*b9df5ad1SAndroid Build Coastguard Workerdef jidentifier(what):
637*b9df5ad1SAndroid Build Coastguard Worker  """
638*b9df5ad1SAndroid Build Coastguard Worker  Convert the input string into a valid Java identifier.
639*b9df5ad1SAndroid Build Coastguard Worker
640*b9df5ad1SAndroid Build Coastguard Worker  Args:
641*b9df5ad1SAndroid Build Coastguard Worker    what: any identifier string
642*b9df5ad1SAndroid Build Coastguard Worker
643*b9df5ad1SAndroid Build Coastguard Worker  Returns:
644*b9df5ad1SAndroid Build Coastguard Worker    String with added underscores if necessary.
645*b9df5ad1SAndroid Build Coastguard Worker  """
646*b9df5ad1SAndroid Build Coastguard Worker  if re.match("\d", what):
647*b9df5ad1SAndroid Build Coastguard Worker    return "_%s" %what
648*b9df5ad1SAndroid Build Coastguard Worker  else:
649*b9df5ad1SAndroid Build Coastguard Worker    return what
650*b9df5ad1SAndroid Build Coastguard Worker
651*b9df5ad1SAndroid Build Coastguard Workerdef enum_calculate_value_string(enum_value):
652*b9df5ad1SAndroid Build Coastguard Worker  """
653*b9df5ad1SAndroid Build Coastguard Worker  Calculate the value of the enum, even if it does not have one explicitly
654*b9df5ad1SAndroid Build Coastguard Worker  defined.
655*b9df5ad1SAndroid Build Coastguard Worker
656*b9df5ad1SAndroid Build Coastguard Worker  This looks back for the first enum value that has a predefined value and then
657*b9df5ad1SAndroid Build Coastguard Worker  applies addition until we get the right value, using C-enum semantics.
658*b9df5ad1SAndroid Build Coastguard Worker
659*b9df5ad1SAndroid Build Coastguard Worker  Args:
660*b9df5ad1SAndroid Build Coastguard Worker    enum_value: an EnumValue node with a valid Enum parent
661*b9df5ad1SAndroid Build Coastguard Worker
662*b9df5ad1SAndroid Build Coastguard Worker  Example:
663*b9df5ad1SAndroid Build Coastguard Worker    <enum>
664*b9df5ad1SAndroid Build Coastguard Worker      <value>X</value>
665*b9df5ad1SAndroid Build Coastguard Worker      <value id="5">Y</value>
666*b9df5ad1SAndroid Build Coastguard Worker      <value>Z</value>
667*b9df5ad1SAndroid Build Coastguard Worker    </enum>
668*b9df5ad1SAndroid Build Coastguard Worker
669*b9df5ad1SAndroid Build Coastguard Worker    enum_calculate_value_string(X) == '0'
670*b9df5ad1SAndroid Build Coastguard Worker    enum_calculate_Value_string(Y) == '5'
671*b9df5ad1SAndroid Build Coastguard Worker    enum_calculate_value_string(Z) == '6'
672*b9df5ad1SAndroid Build Coastguard Worker
673*b9df5ad1SAndroid Build Coastguard Worker  Returns:
674*b9df5ad1SAndroid Build Coastguard Worker    String that represents the enum value as an integer literal.
675*b9df5ad1SAndroid Build Coastguard Worker  """
676*b9df5ad1SAndroid Build Coastguard Worker
677*b9df5ad1SAndroid Build Coastguard Worker  enum_value_siblings = list(enum_value.parent.values)
678*b9df5ad1SAndroid Build Coastguard Worker  this_index = enum_value_siblings.index(enum_value)
679*b9df5ad1SAndroid Build Coastguard Worker
680*b9df5ad1SAndroid Build Coastguard Worker  def is_hex_string(instr):
681*b9df5ad1SAndroid Build Coastguard Worker    return bool(re.match('0x[a-f0-9]+$', instr, re.IGNORECASE))
682*b9df5ad1SAndroid Build Coastguard Worker
683*b9df5ad1SAndroid Build Coastguard Worker  base_value = 0
684*b9df5ad1SAndroid Build Coastguard Worker  base_offset = 0
685*b9df5ad1SAndroid Build Coastguard Worker  emit_as_hex = False
686*b9df5ad1SAndroid Build Coastguard Worker
687*b9df5ad1SAndroid Build Coastguard Worker  this_id = enum_value_siblings[this_index].id
688*b9df5ad1SAndroid Build Coastguard Worker  while this_index != 0 and not this_id:
689*b9df5ad1SAndroid Build Coastguard Worker    this_index -= 1
690*b9df5ad1SAndroid Build Coastguard Worker    base_offset += 1
691*b9df5ad1SAndroid Build Coastguard Worker    this_id = enum_value_siblings[this_index].id
692*b9df5ad1SAndroid Build Coastguard Worker
693*b9df5ad1SAndroid Build Coastguard Worker  if this_id:
694*b9df5ad1SAndroid Build Coastguard Worker    base_value = int(this_id, 0)  # guess base
695*b9df5ad1SAndroid Build Coastguard Worker    emit_as_hex = is_hex_string(this_id)
696*b9df5ad1SAndroid Build Coastguard Worker
697*b9df5ad1SAndroid Build Coastguard Worker  if emit_as_hex:
698*b9df5ad1SAndroid Build Coastguard Worker    return "0x%X" %(base_value + base_offset)
699*b9df5ad1SAndroid Build Coastguard Worker  else:
700*b9df5ad1SAndroid Build Coastguard Worker    return "%d" %(base_value + base_offset)
701*b9df5ad1SAndroid Build Coastguard Worker
702*b9df5ad1SAndroid Build Coastguard Workerdef enumerate_with_last(iterable):
703*b9df5ad1SAndroid Build Coastguard Worker  """
704*b9df5ad1SAndroid Build Coastguard Worker  Enumerate a sequence of iterable, while knowing if this element is the last in
705*b9df5ad1SAndroid Build Coastguard Worker  the sequence or not.
706*b9df5ad1SAndroid Build Coastguard Worker
707*b9df5ad1SAndroid Build Coastguard Worker  Args:
708*b9df5ad1SAndroid Build Coastguard Worker    iterable: an Iterable of some sequence
709*b9df5ad1SAndroid Build Coastguard Worker
710*b9df5ad1SAndroid Build Coastguard Worker  Yields:
711*b9df5ad1SAndroid Build Coastguard Worker    (element, bool) where the bool is True iff the element is last in the seq.
712*b9df5ad1SAndroid Build Coastguard Worker  """
713*b9df5ad1SAndroid Build Coastguard Worker  it = (i for i in iterable)
714*b9df5ad1SAndroid Build Coastguard Worker
715*b9df5ad1SAndroid Build Coastguard Worker  try:
716*b9df5ad1SAndroid Build Coastguard Worker    first = next(it)  # OK: raises exception if it is empty
717*b9df5ad1SAndroid Build Coastguard Worker  except StopIteration:
718*b9df5ad1SAndroid Build Coastguard Worker    return
719*b9df5ad1SAndroid Build Coastguard Worker
720*b9df5ad1SAndroid Build Coastguard Worker  second = first  # for when we have only 1 element in iterable
721*b9df5ad1SAndroid Build Coastguard Worker
722*b9df5ad1SAndroid Build Coastguard Worker  try:
723*b9df5ad1SAndroid Build Coastguard Worker    while True:
724*b9df5ad1SAndroid Build Coastguard Worker      second = next(it)
725*b9df5ad1SAndroid Build Coastguard Worker      # more elements remaining.
726*b9df5ad1SAndroid Build Coastguard Worker      yield (first, False)
727*b9df5ad1SAndroid Build Coastguard Worker      first = second
728*b9df5ad1SAndroid Build Coastguard Worker  except StopIteration:
729*b9df5ad1SAndroid Build Coastguard Worker    # last element. no more elements left
730*b9df5ad1SAndroid Build Coastguard Worker    yield (second, True)
731*b9df5ad1SAndroid Build Coastguard Worker
732*b9df5ad1SAndroid Build Coastguard Workerdef pascal_case(what):
733*b9df5ad1SAndroid Build Coastguard Worker  """
734*b9df5ad1SAndroid Build Coastguard Worker  Convert the first letter of a string to uppercase, to make the identifier
735*b9df5ad1SAndroid Build Coastguard Worker  conform to PascalCase.
736*b9df5ad1SAndroid Build Coastguard Worker
737*b9df5ad1SAndroid Build Coastguard Worker  If there are dots, remove the dots, and capitalize the letter following
738*b9df5ad1SAndroid Build Coastguard Worker  where the dot was. Letters that weren't following dots are left unchanged,
739*b9df5ad1SAndroid Build Coastguard Worker  except for the first letter of the string (which is made upper-case).
740*b9df5ad1SAndroid Build Coastguard Worker
741*b9df5ad1SAndroid Build Coastguard Worker  Args:
742*b9df5ad1SAndroid Build Coastguard Worker    what: a string representing some identifier
743*b9df5ad1SAndroid Build Coastguard Worker
744*b9df5ad1SAndroid Build Coastguard Worker  Returns:
745*b9df5ad1SAndroid Build Coastguard Worker    String with first letter capitalized
746*b9df5ad1SAndroid Build Coastguard Worker
747*b9df5ad1SAndroid Build Coastguard Worker  Example:
748*b9df5ad1SAndroid Build Coastguard Worker    pascal_case("helloWorld") == "HelloWorld"
749*b9df5ad1SAndroid Build Coastguard Worker    pascal_case("foo") == "Foo"
750*b9df5ad1SAndroid Build Coastguard Worker    pascal_case("hello.world") = "HelloWorld"
751*b9df5ad1SAndroid Build Coastguard Worker    pascal_case("fooBar.fooBar") = "FooBarFooBar"
752*b9df5ad1SAndroid Build Coastguard Worker  """
753*b9df5ad1SAndroid Build Coastguard Worker  return "".join([s[0:1].upper() + s[1:] for s in what.split('.')])
754*b9df5ad1SAndroid Build Coastguard Worker
755*b9df5ad1SAndroid Build Coastguard Workerdef jkey_identifier(what):
756*b9df5ad1SAndroid Build Coastguard Worker  """
757*b9df5ad1SAndroid Build Coastguard Worker  Return a Java identifier from a property name.
758*b9df5ad1SAndroid Build Coastguard Worker
759*b9df5ad1SAndroid Build Coastguard Worker  Args:
760*b9df5ad1SAndroid Build Coastguard Worker    what: a string representing a property name.
761*b9df5ad1SAndroid Build Coastguard Worker
762*b9df5ad1SAndroid Build Coastguard Worker  Returns:
763*b9df5ad1SAndroid Build Coastguard Worker    Java identifier corresponding to the property name. May need to be
764*b9df5ad1SAndroid Build Coastguard Worker    prepended with the appropriate Java class name by the caller of this
765*b9df5ad1SAndroid Build Coastguard Worker    function. Note that the outer namespace is stripped from the property
766*b9df5ad1SAndroid Build Coastguard Worker    name.
767*b9df5ad1SAndroid Build Coastguard Worker
768*b9df5ad1SAndroid Build Coastguard Worker  Example:
769*b9df5ad1SAndroid Build Coastguard Worker    jkey_identifier("android.lens.facing") == "LENS_FACING"
770*b9df5ad1SAndroid Build Coastguard Worker  """
771*b9df5ad1SAndroid Build Coastguard Worker  return csym(what[what.find('.') + 1:])
772*b9df5ad1SAndroid Build Coastguard Worker
773*b9df5ad1SAndroid Build Coastguard Workerdef jenum_value(enum_entry, enum_value):
774*b9df5ad1SAndroid Build Coastguard Worker  """
775*b9df5ad1SAndroid Build Coastguard Worker  Calculate the Java name for an integer enum value
776*b9df5ad1SAndroid Build Coastguard Worker
777*b9df5ad1SAndroid Build Coastguard Worker  Args:
778*b9df5ad1SAndroid Build Coastguard Worker    enum: An enum-typed Entry node
779*b9df5ad1SAndroid Build Coastguard Worker    value: An EnumValue node for the enum
780*b9df5ad1SAndroid Build Coastguard Worker
781*b9df5ad1SAndroid Build Coastguard Worker  Returns:
782*b9df5ad1SAndroid Build Coastguard Worker    String representing the Java symbol
783*b9df5ad1SAndroid Build Coastguard Worker  """
784*b9df5ad1SAndroid Build Coastguard Worker
785*b9df5ad1SAndroid Build Coastguard Worker  cname = csym(enum_entry.name)
786*b9df5ad1SAndroid Build Coastguard Worker  return cname[cname.find('_') + 1:] + '_' + enum_value.name
787*b9df5ad1SAndroid Build Coastguard Worker
788*b9df5ad1SAndroid Build Coastguard Workerdef generate_extra_javadoc_detail(entry):
789*b9df5ad1SAndroid Build Coastguard Worker  """
790*b9df5ad1SAndroid Build Coastguard Worker  Returns a function to add extra details for an entry into a string for inclusion into
791*b9df5ad1SAndroid Build Coastguard Worker  javadoc. Adds information about units, the list of enum values for this key, and the valid
792*b9df5ad1SAndroid Build Coastguard Worker  range.
793*b9df5ad1SAndroid Build Coastguard Worker  """
794*b9df5ad1SAndroid Build Coastguard Worker  def inner(text):
795*b9df5ad1SAndroid Build Coastguard Worker    if entry.units and not (entry.typedef and entry.typedef.name == 'string'):
796*b9df5ad1SAndroid Build Coastguard Worker      text += '\n\n<b>Units</b>: %s\n' % (dedent(entry.units))
797*b9df5ad1SAndroid Build Coastguard Worker    if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')):
798*b9df5ad1SAndroid Build Coastguard Worker      text += '\n\n<b>Possible values:</b>\n<ul>\n'
799*b9df5ad1SAndroid Build Coastguard Worker      for value in entry.enum.values:
800*b9df5ad1SAndroid Build Coastguard Worker        if not value.hidden and (value.aconfig_flag == entry.aconfig_flag):
801*b9df5ad1SAndroid Build Coastguard Worker          text += '  <li>{@link #%s %s}</li>\n' % ( jenum_value(entry, value ), value.name )
802*b9df5ad1SAndroid Build Coastguard Worker      text += '</ul>\n'
803*b9df5ad1SAndroid Build Coastguard Worker    if entry.range:
804*b9df5ad1SAndroid Build Coastguard Worker      if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')):
805*b9df5ad1SAndroid Build Coastguard Worker        text += '\n\n<b>Available values for this device:</b><br>\n'
806*b9df5ad1SAndroid Build Coastguard Worker      else:
807*b9df5ad1SAndroid Build Coastguard Worker        text += '\n\n<b>Range of valid values:</b><br>\n'
808*b9df5ad1SAndroid Build Coastguard Worker      text += '%s\n' % (dedent(entry.range))
809*b9df5ad1SAndroid Build Coastguard Worker    if entry.hwlevel != 'legacy': # covers any of (None, 'limited', 'full')
810*b9df5ad1SAndroid Build Coastguard Worker      text += '\n\n<b>Optional</b> - The value for this key may be {@code null} on some devices.\n'
811*b9df5ad1SAndroid Build Coastguard Worker    if entry.hwlevel == 'full':
812*b9df5ad1SAndroid Build Coastguard Worker      text += \
813*b9df5ad1SAndroid Build Coastguard Worker        '\n<b>Full capability</b> - \n' + \
814*b9df5ad1SAndroid Build Coastguard Worker        'Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the\n' + \
815*b9df5ad1SAndroid Build Coastguard Worker        'android.info.supportedHardwareLevel key\n'
816*b9df5ad1SAndroid Build Coastguard Worker    if entry.hwlevel == 'limited':
817*b9df5ad1SAndroid Build Coastguard Worker      text += \
818*b9df5ad1SAndroid Build Coastguard Worker        '\n<b>Limited capability</b> - \n' + \
819*b9df5ad1SAndroid Build Coastguard Worker        'Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the\n' + \
820*b9df5ad1SAndroid Build Coastguard Worker        'android.info.supportedHardwareLevel key\n'
821*b9df5ad1SAndroid Build Coastguard Worker    if entry.hwlevel == 'legacy':
822*b9df5ad1SAndroid Build Coastguard Worker      text += "\nThis key is available on all devices."
823*b9df5ad1SAndroid Build Coastguard Worker    if entry.permission_needed == "true":
824*b9df5ad1SAndroid Build Coastguard Worker      text += "\n\n<b>Permission {@link android.Manifest.permission#CAMERA} is needed to access this property</b>\n\n"
825*b9df5ad1SAndroid Build Coastguard Worker
826*b9df5ad1SAndroid Build Coastguard Worker    return text
827*b9df5ad1SAndroid Build Coastguard Worker  return inner
828*b9df5ad1SAndroid Build Coastguard Worker
829*b9df5ad1SAndroid Build Coastguard Worker
830*b9df5ad1SAndroid Build Coastguard Workerdef javadoc(metadata, indent = 4):
831*b9df5ad1SAndroid Build Coastguard Worker  """
832*b9df5ad1SAndroid Build Coastguard Worker  Returns a function to format a markdown syntax text block as a
833*b9df5ad1SAndroid Build Coastguard Worker  javadoc comment section, given a set of metadata
834*b9df5ad1SAndroid Build Coastguard Worker
835*b9df5ad1SAndroid Build Coastguard Worker  Args:
836*b9df5ad1SAndroid Build Coastguard Worker    metadata: A Metadata instance, representing the top-level root
837*b9df5ad1SAndroid Build Coastguard Worker      of the metadata for cross-referencing
838*b9df5ad1SAndroid Build Coastguard Worker    indent: baseline level of indentation for javadoc block
839*b9df5ad1SAndroid Build Coastguard Worker  Returns:
840*b9df5ad1SAndroid Build Coastguard Worker    A function that transforms a String text block as follows:
841*b9df5ad1SAndroid Build Coastguard Worker    - Indent and * for insertion into a Javadoc comment block
842*b9df5ad1SAndroid Build Coastguard Worker    - Trailing whitespace removed
843*b9df5ad1SAndroid Build Coastguard Worker    - Entire body rendered via markdown to generate HTML
844*b9df5ad1SAndroid Build Coastguard Worker    - All tag names converted to appropriate Javadoc {@link} with @see
845*b9df5ad1SAndroid Build Coastguard Worker      for each tag
846*b9df5ad1SAndroid Build Coastguard Worker
847*b9df5ad1SAndroid Build Coastguard Worker  Example:
848*b9df5ad1SAndroid Build Coastguard Worker    "This is a comment for Javadoc\n" +
849*b9df5ad1SAndroid Build Coastguard Worker    "     with multiple lines, that should be   \n" +
850*b9df5ad1SAndroid Build Coastguard Worker    "     formatted better\n" +
851*b9df5ad1SAndroid Build Coastguard Worker    "\n" +
852*b9df5ad1SAndroid Build Coastguard Worker    "    That covers multiple lines as well\n"
853*b9df5ad1SAndroid Build Coastguard Worker    "    And references android.control.mode\n"
854*b9df5ad1SAndroid Build Coastguard Worker
855*b9df5ad1SAndroid Build Coastguard Worker    transforms to
856*b9df5ad1SAndroid Build Coastguard Worker    "    * <p>This is a comment for Javadoc\n" +
857*b9df5ad1SAndroid Build Coastguard Worker    "    * with multiple lines, that should be\n" +
858*b9df5ad1SAndroid Build Coastguard Worker    "    * formatted better</p>\n" +
859*b9df5ad1SAndroid Build Coastguard Worker    "    * <p>That covers multiple lines as well</p>\n" +
860*b9df5ad1SAndroid Build Coastguard Worker    "    * and references {@link CaptureRequest#CONTROL_MODE android.control.mode}\n" +
861*b9df5ad1SAndroid Build Coastguard Worker    "    *\n" +
862*b9df5ad1SAndroid Build Coastguard Worker    "    * @see CaptureRequest#CONTROL_MODE\n"
863*b9df5ad1SAndroid Build Coastguard Worker  """
864*b9df5ad1SAndroid Build Coastguard Worker  def javadoc_formatter(text):
865*b9df5ad1SAndroid Build Coastguard Worker    comment_prefix = " " * indent + " * "
866*b9df5ad1SAndroid Build Coastguard Worker
867*b9df5ad1SAndroid Build Coastguard Worker    # render with markdown => HTML
868*b9df5ad1SAndroid Build Coastguard Worker    javatext = md(text, JAVADOC_IMAGE_SRC_METADATA)
869*b9df5ad1SAndroid Build Coastguard Worker
870*b9df5ad1SAndroid Build Coastguard Worker    # Identity transform for javadoc links
871*b9df5ad1SAndroid Build Coastguard Worker    def javadoc_link_filter(target, target_ndk, shortname):
872*b9df5ad1SAndroid Build Coastguard Worker      return '{@link %s %s}' % (target, shortname)
873*b9df5ad1SAndroid Build Coastguard Worker
874*b9df5ad1SAndroid Build Coastguard Worker    javatext = filter_links(javatext, javadoc_link_filter)
875*b9df5ad1SAndroid Build Coastguard Worker
876*b9df5ad1SAndroid Build Coastguard Worker    # Crossref tag names
877*b9df5ad1SAndroid Build Coastguard Worker    kind_mapping = {
878*b9df5ad1SAndroid Build Coastguard Worker        'static': 'CameraCharacteristics',
879*b9df5ad1SAndroid Build Coastguard Worker        'dynamic': 'CaptureResult',
880*b9df5ad1SAndroid Build Coastguard Worker        'controls': 'CaptureRequest' }
881*b9df5ad1SAndroid Build Coastguard Worker
882*b9df5ad1SAndroid Build Coastguard Worker    # Convert metadata entry "android.x.y.z" to form
883*b9df5ad1SAndroid Build Coastguard Worker    # "{@link CaptureRequest#X_Y_Z android.x.y.z}"
884*b9df5ad1SAndroid Build Coastguard Worker    def javadoc_crossref_filter(node):
885*b9df5ad1SAndroid Build Coastguard Worker      if node.applied_visibility in ('public', 'java_public', 'fwk_java_public', 'fwk_public',\
886*b9df5ad1SAndroid Build Coastguard Worker                                     'fwk_system_public'):
887*b9df5ad1SAndroid Build Coastguard Worker        return '{@link %s#%s %s}' % (kind_mapping[node.kind],
888*b9df5ad1SAndroid Build Coastguard Worker                                     jkey_identifier(node.name),
889*b9df5ad1SAndroid Build Coastguard Worker                                     node.name)
890*b9df5ad1SAndroid Build Coastguard Worker      else:
891*b9df5ad1SAndroid Build Coastguard Worker        return node.name
892*b9df5ad1SAndroid Build Coastguard Worker
893*b9df5ad1SAndroid Build Coastguard Worker    # For each public tag "android.x.y.z" referenced, add a
894*b9df5ad1SAndroid Build Coastguard Worker    # "@see CaptureRequest#X_Y_Z"
895*b9df5ad1SAndroid Build Coastguard Worker    def javadoc_crossref_see_filter(node_set):
896*b9df5ad1SAndroid Build Coastguard Worker      node_set = (x for x in node_set if x.applied_visibility in \
897*b9df5ad1SAndroid Build Coastguard Worker                  ('public', 'java_public', 'fwk_java_public', 'fwk_public', 'fwk_system_public'))
898*b9df5ad1SAndroid Build Coastguard Worker
899*b9df5ad1SAndroid Build Coastguard Worker      text = '\n'
900*b9df5ad1SAndroid Build Coastguard Worker      for node in node_set:
901*b9df5ad1SAndroid Build Coastguard Worker        text = text + '\n@see %s#%s' % (kind_mapping[node.kind],
902*b9df5ad1SAndroid Build Coastguard Worker                                      jkey_identifier(node.name))
903*b9df5ad1SAndroid Build Coastguard Worker
904*b9df5ad1SAndroid Build Coastguard Worker      return text if text != '\n' else ''
905*b9df5ad1SAndroid Build Coastguard Worker
906*b9df5ad1SAndroid Build Coastguard Worker    javatext = filter_tags(javatext, metadata, javadoc_crossref_filter, javadoc_crossref_see_filter)
907*b9df5ad1SAndroid Build Coastguard Worker
908*b9df5ad1SAndroid Build Coastguard Worker    def line_filter(line):
909*b9df5ad1SAndroid Build Coastguard Worker      # Indent each line
910*b9df5ad1SAndroid Build Coastguard Worker      # Add ' * ' to it for stylistic reasons
911*b9df5ad1SAndroid Build Coastguard Worker      # Strip right side of trailing whitespace
912*b9df5ad1SAndroid Build Coastguard Worker      return (comment_prefix + line).rstrip()
913*b9df5ad1SAndroid Build Coastguard Worker
914*b9df5ad1SAndroid Build Coastguard Worker    # Process each line with above filter
915*b9df5ad1SAndroid Build Coastguard Worker    javatext = "\n".join(line_filter(i) for i in javatext.split("\n")) + "\n"
916*b9df5ad1SAndroid Build Coastguard Worker
917*b9df5ad1SAndroid Build Coastguard Worker    return javatext
918*b9df5ad1SAndroid Build Coastguard Worker
919*b9df5ad1SAndroid Build Coastguard Worker  return javadoc_formatter
920*b9df5ad1SAndroid Build Coastguard Worker
921*b9df5ad1SAndroid Build Coastguard Workerdef ndkdoc(metadata, indent = 4):
922*b9df5ad1SAndroid Build Coastguard Worker  """
923*b9df5ad1SAndroid Build Coastguard Worker  Returns a function to format a markdown syntax text block as a
924*b9df5ad1SAndroid Build Coastguard Worker  NDK camera API C/C++ comment section, given a set of metadata
925*b9df5ad1SAndroid Build Coastguard Worker
926*b9df5ad1SAndroid Build Coastguard Worker  Args:
927*b9df5ad1SAndroid Build Coastguard Worker    metadata: A Metadata instance, representing the top-level root
928*b9df5ad1SAndroid Build Coastguard Worker      of the metadata for cross-referencing
929*b9df5ad1SAndroid Build Coastguard Worker    indent: baseline level of indentation for comment block
930*b9df5ad1SAndroid Build Coastguard Worker  Returns:
931*b9df5ad1SAndroid Build Coastguard Worker    A function that transforms a String text block as follows:
932*b9df5ad1SAndroid Build Coastguard Worker    - Indent and * for insertion into a comment block
933*b9df5ad1SAndroid Build Coastguard Worker    - Trailing whitespace removed
934*b9df5ad1SAndroid Build Coastguard Worker    - Entire body rendered via markdown
935*b9df5ad1SAndroid Build Coastguard Worker    - All tag names converted to appropriate NDK tag name for each tag
936*b9df5ad1SAndroid Build Coastguard Worker
937*b9df5ad1SAndroid Build Coastguard Worker  Example:
938*b9df5ad1SAndroid Build Coastguard Worker    "This is a comment for NDK\n" +
939*b9df5ad1SAndroid Build Coastguard Worker    "     with multiple lines, that should be   \n" +
940*b9df5ad1SAndroid Build Coastguard Worker    "     formatted better\n" +
941*b9df5ad1SAndroid Build Coastguard Worker    "\n" +
942*b9df5ad1SAndroid Build Coastguard Worker    "    That covers multiple lines as well\n"
943*b9df5ad1SAndroid Build Coastguard Worker    "    And references android.control.mode\n"
944*b9df5ad1SAndroid Build Coastguard Worker
945*b9df5ad1SAndroid Build Coastguard Worker    transforms to
946*b9df5ad1SAndroid Build Coastguard Worker    "    * This is a comment for NDK\n" +
947*b9df5ad1SAndroid Build Coastguard Worker    "    * with multiple lines, that should be\n" +
948*b9df5ad1SAndroid Build Coastguard Worker    "    * formatted better\n" +
949*b9df5ad1SAndroid Build Coastguard Worker    "    * That covers multiple lines as well\n" +
950*b9df5ad1SAndroid Build Coastguard Worker    "    * and references ACAMERA_CONTROL_MODE\n" +
951*b9df5ad1SAndroid Build Coastguard Worker    "    *\n" +
952*b9df5ad1SAndroid Build Coastguard Worker    "    * @see ACAMERA_CONTROL_MODE\n"
953*b9df5ad1SAndroid Build Coastguard Worker  """
954*b9df5ad1SAndroid Build Coastguard Worker  def ndkdoc_formatter(text):
955*b9df5ad1SAndroid Build Coastguard Worker    # render with markdown => HTML
956*b9df5ad1SAndroid Build Coastguard Worker    # Turn off the table plugin since doxygen doesn't recognize generated <thead> <tbody> tags
957*b9df5ad1SAndroid Build Coastguard Worker    ndktext = md(text, NDKDOC_IMAGE_SRC_METADATA, False)
958*b9df5ad1SAndroid Build Coastguard Worker
959*b9df5ad1SAndroid Build Coastguard Worker    # Simple transform for ndk doc links
960*b9df5ad1SAndroid Build Coastguard Worker    def ndkdoc_link_filter(target, target_ndk, shortname):
961*b9df5ad1SAndroid Build Coastguard Worker      if target_ndk is not None:
962*b9df5ad1SAndroid Build Coastguard Worker        return '{@link %s %s}' % (target_ndk, shortname)
963*b9df5ad1SAndroid Build Coastguard Worker
964*b9df5ad1SAndroid Build Coastguard Worker      # Create HTML link to Javadoc
965*b9df5ad1SAndroid Build Coastguard Worker      if shortname == '':
966*b9df5ad1SAndroid Build Coastguard Worker        lastdot = target.rfind('.')
967*b9df5ad1SAndroid Build Coastguard Worker        if lastdot == -1:
968*b9df5ad1SAndroid Build Coastguard Worker          shortname = target
969*b9df5ad1SAndroid Build Coastguard Worker        else:
970*b9df5ad1SAndroid Build Coastguard Worker          shortname = target[lastdot + 1:]
971*b9df5ad1SAndroid Build Coastguard Worker
972*b9df5ad1SAndroid Build Coastguard Worker      target = target.replace('.','/')
973*b9df5ad1SAndroid Build Coastguard Worker      if target.find('#') != -1:
974*b9df5ad1SAndroid Build Coastguard Worker        target = target.replace('#','.html#')
975*b9df5ad1SAndroid Build Coastguard Worker      else:
976*b9df5ad1SAndroid Build Coastguard Worker        target = target + '.html'
977*b9df5ad1SAndroid Build Coastguard Worker
978*b9df5ad1SAndroid Build Coastguard Worker      # Work around html links with inner classes.
979*b9df5ad1SAndroid Build Coastguard Worker      target = target.replace('CaptureRequest/Builder', 'CaptureRequest.Builder')
980*b9df5ad1SAndroid Build Coastguard Worker      target = target.replace('Build/VERSION', 'Build.VERSION')
981*b9df5ad1SAndroid Build Coastguard Worker
982*b9df5ad1SAndroid Build Coastguard Worker      return '<a href="https://developer.android.com/reference/%s">%s</a>' % (target, shortname)
983*b9df5ad1SAndroid Build Coastguard Worker
984*b9df5ad1SAndroid Build Coastguard Worker    ndktext = filter_links(ndktext, ndkdoc_link_filter)
985*b9df5ad1SAndroid Build Coastguard Worker
986*b9df5ad1SAndroid Build Coastguard Worker    # Convert metadata entry "android.x.y.z" to form
987*b9df5ad1SAndroid Build Coastguard Worker    # NDK tag format of "ACAMERA_X_Y_Z"
988*b9df5ad1SAndroid Build Coastguard Worker    def ndkdoc_crossref_filter(node):
989*b9df5ad1SAndroid Build Coastguard Worker      if node.applied_ndk_visible == 'true':
990*b9df5ad1SAndroid Build Coastguard Worker        return csym(ndk(node.name))
991*b9df5ad1SAndroid Build Coastguard Worker      else:
992*b9df5ad1SAndroid Build Coastguard Worker        return node.name
993*b9df5ad1SAndroid Build Coastguard Worker
994*b9df5ad1SAndroid Build Coastguard Worker    # For each public tag "android.x.y.z" referenced, add a
995*b9df5ad1SAndroid Build Coastguard Worker    # "@see ACAMERA_X_Y_Z"
996*b9df5ad1SAndroid Build Coastguard Worker    def ndkdoc_crossref_see_filter(node_set):
997*b9df5ad1SAndroid Build Coastguard Worker      node_set = (x for x in node_set if x.applied_ndk_visible == 'true')
998*b9df5ad1SAndroid Build Coastguard Worker
999*b9df5ad1SAndroid Build Coastguard Worker      text = '\n'
1000*b9df5ad1SAndroid Build Coastguard Worker      for node in node_set:
1001*b9df5ad1SAndroid Build Coastguard Worker        text = text + '\n@see %s' % (csym(ndk(node.name)))
1002*b9df5ad1SAndroid Build Coastguard Worker
1003*b9df5ad1SAndroid Build Coastguard Worker      return text if text != '\n' else ''
1004*b9df5ad1SAndroid Build Coastguard Worker
1005*b9df5ad1SAndroid Build Coastguard Worker    ndktext = filter_tags(ndktext, metadata, ndkdoc_crossref_filter, ndkdoc_crossref_see_filter)
1006*b9df5ad1SAndroid Build Coastguard Worker
1007*b9df5ad1SAndroid Build Coastguard Worker    ndktext = ndk_replace_tag_wildcards(ndktext, metadata)
1008*b9df5ad1SAndroid Build Coastguard Worker
1009*b9df5ad1SAndroid Build Coastguard Worker    comment_prefix = " " * indent + " * ";
1010*b9df5ad1SAndroid Build Coastguard Worker
1011*b9df5ad1SAndroid Build Coastguard Worker    def line_filter(line):
1012*b9df5ad1SAndroid Build Coastguard Worker      # Indent each line
1013*b9df5ad1SAndroid Build Coastguard Worker      # Add ' * ' to it for stylistic reasons
1014*b9df5ad1SAndroid Build Coastguard Worker      # Strip right side of trailing whitespace
1015*b9df5ad1SAndroid Build Coastguard Worker      return (comment_prefix + line).rstrip()
1016*b9df5ad1SAndroid Build Coastguard Worker
1017*b9df5ad1SAndroid Build Coastguard Worker    # Process each line with above filter
1018*b9df5ad1SAndroid Build Coastguard Worker    ndktext = "\n".join(line_filter(i) for i in ndktext.split("\n")) + "\n"
1019*b9df5ad1SAndroid Build Coastguard Worker
1020*b9df5ad1SAndroid Build Coastguard Worker    return ndktext
1021*b9df5ad1SAndroid Build Coastguard Worker
1022*b9df5ad1SAndroid Build Coastguard Worker  return ndkdoc_formatter
1023*b9df5ad1SAndroid Build Coastguard Worker
1024*b9df5ad1SAndroid Build Coastguard Workerdef hidldoc(metadata, indent = 4):
1025*b9df5ad1SAndroid Build Coastguard Worker  """
1026*b9df5ad1SAndroid Build Coastguard Worker  Returns a function to format a markdown syntax text block as a
1027*b9df5ad1SAndroid Build Coastguard Worker  HIDL camera HAL module C/C++ comment section, given a set of metadata
1028*b9df5ad1SAndroid Build Coastguard Worker
1029*b9df5ad1SAndroid Build Coastguard Worker  Args:
1030*b9df5ad1SAndroid Build Coastguard Worker    metadata: A Metadata instance, representing the top-level root
1031*b9df5ad1SAndroid Build Coastguard Worker      of the metadata for cross-referencing
1032*b9df5ad1SAndroid Build Coastguard Worker    indent: baseline level of indentation for comment block
1033*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1034*b9df5ad1SAndroid Build Coastguard Worker    A function that transforms a String text block as follows:
1035*b9df5ad1SAndroid Build Coastguard Worker    - Indent and * for insertion into a comment block
1036*b9df5ad1SAndroid Build Coastguard Worker    - Trailing whitespace removed
1037*b9df5ad1SAndroid Build Coastguard Worker    - Entire body rendered via markdown
1038*b9df5ad1SAndroid Build Coastguard Worker    - All tag names converted to appropriate HIDL tag name for each tag
1039*b9df5ad1SAndroid Build Coastguard Worker
1040*b9df5ad1SAndroid Build Coastguard Worker  Example:
1041*b9df5ad1SAndroid Build Coastguard Worker    "This is a comment for NDK\n" +
1042*b9df5ad1SAndroid Build Coastguard Worker    "     with multiple lines, that should be   \n" +
1043*b9df5ad1SAndroid Build Coastguard Worker    "     formatted better\n" +
1044*b9df5ad1SAndroid Build Coastguard Worker    "\n" +
1045*b9df5ad1SAndroid Build Coastguard Worker    "    That covers multiple lines as well\n"
1046*b9df5ad1SAndroid Build Coastguard Worker    "    And references android.control.mode\n"
1047*b9df5ad1SAndroid Build Coastguard Worker
1048*b9df5ad1SAndroid Build Coastguard Worker    transforms to
1049*b9df5ad1SAndroid Build Coastguard Worker    "    * This is a comment for NDK\n" +
1050*b9df5ad1SAndroid Build Coastguard Worker    "    * with multiple lines, that should be\n" +
1051*b9df5ad1SAndroid Build Coastguard Worker    "    * formatted better\n" +
1052*b9df5ad1SAndroid Build Coastguard Worker    "    * That covers multiple lines as well\n" +
1053*b9df5ad1SAndroid Build Coastguard Worker    "    * and references ANDROID_CONTROL_MODE\n" +
1054*b9df5ad1SAndroid Build Coastguard Worker    "    *\n" +
1055*b9df5ad1SAndroid Build Coastguard Worker    "    * @see ANDROID_CONTROL_MODE\n"
1056*b9df5ad1SAndroid Build Coastguard Worker  """
1057*b9df5ad1SAndroid Build Coastguard Worker  def hidldoc_formatter(text):
1058*b9df5ad1SAndroid Build Coastguard Worker    # render with markdown => HTML
1059*b9df5ad1SAndroid Build Coastguard Worker    # Turn off the table plugin since doxygen doesn't recognize generated <thead> <tbody> tags
1060*b9df5ad1SAndroid Build Coastguard Worker    hidltext = md(text, NDKDOC_IMAGE_SRC_METADATA, False)
1061*b9df5ad1SAndroid Build Coastguard Worker
1062*b9df5ad1SAndroid Build Coastguard Worker    # Simple transform for hidl doc links
1063*b9df5ad1SAndroid Build Coastguard Worker    def hidldoc_link_filter(target, target_ndk, shortname):
1064*b9df5ad1SAndroid Build Coastguard Worker      if target_ndk is not None:
1065*b9df5ad1SAndroid Build Coastguard Worker        return '{@link %s %s}' % (target_ndk, shortname)
1066*b9df5ad1SAndroid Build Coastguard Worker
1067*b9df5ad1SAndroid Build Coastguard Worker      # Create HTML link to Javadoc
1068*b9df5ad1SAndroid Build Coastguard Worker      if shortname == '':
1069*b9df5ad1SAndroid Build Coastguard Worker        lastdot = target.rfind('.')
1070*b9df5ad1SAndroid Build Coastguard Worker        if lastdot == -1:
1071*b9df5ad1SAndroid Build Coastguard Worker          shortname = target
1072*b9df5ad1SAndroid Build Coastguard Worker        else:
1073*b9df5ad1SAndroid Build Coastguard Worker          shortname = target[lastdot + 1:]
1074*b9df5ad1SAndroid Build Coastguard Worker
1075*b9df5ad1SAndroid Build Coastguard Worker      target = target.replace('.','/')
1076*b9df5ad1SAndroid Build Coastguard Worker      if target.find('#') != -1:
1077*b9df5ad1SAndroid Build Coastguard Worker        target = target.replace('#','.html#')
1078*b9df5ad1SAndroid Build Coastguard Worker      else:
1079*b9df5ad1SAndroid Build Coastguard Worker        target = target + '.html'
1080*b9df5ad1SAndroid Build Coastguard Worker
1081*b9df5ad1SAndroid Build Coastguard Worker      return '<a href="https://developer.android.com/reference/%s">%s</a>' % (target, shortname)
1082*b9df5ad1SAndroid Build Coastguard Worker
1083*b9df5ad1SAndroid Build Coastguard Worker    hidltext = filter_links(hidltext, hidldoc_link_filter)
1084*b9df5ad1SAndroid Build Coastguard Worker
1085*b9df5ad1SAndroid Build Coastguard Worker    # Convert metadata entry "android.x.y.z" to form
1086*b9df5ad1SAndroid Build Coastguard Worker    # HIDL tag format of "ANDROID_X_Y_Z"
1087*b9df5ad1SAndroid Build Coastguard Worker    def hidldoc_crossref_filter(node):
1088*b9df5ad1SAndroid Build Coastguard Worker      return csym(node.name)
1089*b9df5ad1SAndroid Build Coastguard Worker
1090*b9df5ad1SAndroid Build Coastguard Worker    # For each public tag "android.x.y.z" referenced, add a
1091*b9df5ad1SAndroid Build Coastguard Worker    # "@see ANDROID_X_Y_Z"
1092*b9df5ad1SAndroid Build Coastguard Worker    def hidldoc_crossref_see_filter(node_set):
1093*b9df5ad1SAndroid Build Coastguard Worker      text = '\n'
1094*b9df5ad1SAndroid Build Coastguard Worker      for node in node_set:
1095*b9df5ad1SAndroid Build Coastguard Worker        text = text + '\n@see %s' % (csym(node.name))
1096*b9df5ad1SAndroid Build Coastguard Worker
1097*b9df5ad1SAndroid Build Coastguard Worker      return text if text != '\n' else ''
1098*b9df5ad1SAndroid Build Coastguard Worker
1099*b9df5ad1SAndroid Build Coastguard Worker    hidltext = filter_tags(hidltext, metadata, hidldoc_crossref_filter, hidldoc_crossref_see_filter)
1100*b9df5ad1SAndroid Build Coastguard Worker
1101*b9df5ad1SAndroid Build Coastguard Worker    comment_prefix = " " * indent + " * ";
1102*b9df5ad1SAndroid Build Coastguard Worker
1103*b9df5ad1SAndroid Build Coastguard Worker    def line_filter(line):
1104*b9df5ad1SAndroid Build Coastguard Worker      # Indent each line
1105*b9df5ad1SAndroid Build Coastguard Worker      # Add ' * ' to it for stylistic reasons
1106*b9df5ad1SAndroid Build Coastguard Worker      # Strip right side of trailing whitespace
1107*b9df5ad1SAndroid Build Coastguard Worker      return (comment_prefix + line).rstrip()
1108*b9df5ad1SAndroid Build Coastguard Worker
1109*b9df5ad1SAndroid Build Coastguard Worker    # Process each line with above filter
1110*b9df5ad1SAndroid Build Coastguard Worker    hidltext = "\n".join(line_filter(i) for i in hidltext.split("\n")) + "\n"
1111*b9df5ad1SAndroid Build Coastguard Worker
1112*b9df5ad1SAndroid Build Coastguard Worker    return hidltext
1113*b9df5ad1SAndroid Build Coastguard Worker
1114*b9df5ad1SAndroid Build Coastguard Worker  return hidldoc_formatter
1115*b9df5ad1SAndroid Build Coastguard Worker
1116*b9df5ad1SAndroid Build Coastguard Workerdef dedent(text):
1117*b9df5ad1SAndroid Build Coastguard Worker  """
1118*b9df5ad1SAndroid Build Coastguard Worker  Remove all common indentation from every line but the 0th.
1119*b9df5ad1SAndroid Build Coastguard Worker  This will avoid getting <code> blocks when rendering text via markdown.
1120*b9df5ad1SAndroid Build Coastguard Worker  Ignoring the 0th line will also allow the 0th line not to be aligned.
1121*b9df5ad1SAndroid Build Coastguard Worker
1122*b9df5ad1SAndroid Build Coastguard Worker  Args:
1123*b9df5ad1SAndroid Build Coastguard Worker    text: A string of text to dedent.
1124*b9df5ad1SAndroid Build Coastguard Worker
1125*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1126*b9df5ad1SAndroid Build Coastguard Worker    String dedented by above rules.
1127*b9df5ad1SAndroid Build Coastguard Worker
1128*b9df5ad1SAndroid Build Coastguard Worker  For example:
1129*b9df5ad1SAndroid Build Coastguard Worker    assertEquals("bar\nline1\nline2",   dedent("bar\n  line1\n  line2"))
1130*b9df5ad1SAndroid Build Coastguard Worker    assertEquals("bar\nline1\nline2",   dedent(" bar\n  line1\n  line2"))
1131*b9df5ad1SAndroid Build Coastguard Worker    assertEquals("bar\n  line1\nline2", dedent(" bar\n    line1\n  line2"))
1132*b9df5ad1SAndroid Build Coastguard Worker  """
1133*b9df5ad1SAndroid Build Coastguard Worker  text = textwrap.dedent(text)
1134*b9df5ad1SAndroid Build Coastguard Worker  text_lines = text.split('\n')
1135*b9df5ad1SAndroid Build Coastguard Worker  text_not_first = "\n".join(text_lines[1:])
1136*b9df5ad1SAndroid Build Coastguard Worker  text_not_first = textwrap.dedent(text_not_first)
1137*b9df5ad1SAndroid Build Coastguard Worker  text = text_lines[0] + "\n" + text_not_first
1138*b9df5ad1SAndroid Build Coastguard Worker
1139*b9df5ad1SAndroid Build Coastguard Worker  return text
1140*b9df5ad1SAndroid Build Coastguard Worker
1141*b9df5ad1SAndroid Build Coastguard Workerdef md(text, img_src_prefix="", table_ext=True):
1142*b9df5ad1SAndroid Build Coastguard Worker    """
1143*b9df5ad1SAndroid Build Coastguard Worker    Run text through markdown to produce HTML.
1144*b9df5ad1SAndroid Build Coastguard Worker
1145*b9df5ad1SAndroid Build Coastguard Worker    This also removes all common indentation from every line but the 0th.
1146*b9df5ad1SAndroid Build Coastguard Worker    This will avoid getting <code> blocks in markdown.
1147*b9df5ad1SAndroid Build Coastguard Worker    Ignoring the 0th line will also allow the 0th line not to be aligned.
1148*b9df5ad1SAndroid Build Coastguard Worker
1149*b9df5ad1SAndroid Build Coastguard Worker    Args:
1150*b9df5ad1SAndroid Build Coastguard Worker      text: A markdown-syntax using block of text to format.
1151*b9df5ad1SAndroid Build Coastguard Worker      img_src_prefix: An optional string to prepend to each <img src="target"/>
1152*b9df5ad1SAndroid Build Coastguard Worker
1153*b9df5ad1SAndroid Build Coastguard Worker    Returns:
1154*b9df5ad1SAndroid Build Coastguard Worker      String rendered by markdown and other rules applied (see above).
1155*b9df5ad1SAndroid Build Coastguard Worker
1156*b9df5ad1SAndroid Build Coastguard Worker    For example, this avoids the following situation:
1157*b9df5ad1SAndroid Build Coastguard Worker
1158*b9df5ad1SAndroid Build Coastguard Worker      <!-- Input -->
1159*b9df5ad1SAndroid Build Coastguard Worker
1160*b9df5ad1SAndroid Build Coastguard Worker      <!--- can't use dedent directly since 'foo' has no indent -->
1161*b9df5ad1SAndroid Build Coastguard Worker      <notes>foo
1162*b9df5ad1SAndroid Build Coastguard Worker          bar
1163*b9df5ad1SAndroid Build Coastguard Worker          bar
1164*b9df5ad1SAndroid Build Coastguard Worker      </notes>
1165*b9df5ad1SAndroid Build Coastguard Worker
1166*b9df5ad1SAndroid Build Coastguard Worker      <!-- Bad Output -- >
1167*b9df5ad1SAndroid Build Coastguard Worker      <!-- if no dedent is done generated code looks like -->
1168*b9df5ad1SAndroid Build Coastguard Worker      <p>foo
1169*b9df5ad1SAndroid Build Coastguard Worker        <code><pre>
1170*b9df5ad1SAndroid Build Coastguard Worker          bar
1171*b9df5ad1SAndroid Build Coastguard Worker          bar</pre></code>
1172*b9df5ad1SAndroid Build Coastguard Worker      </p>
1173*b9df5ad1SAndroid Build Coastguard Worker
1174*b9df5ad1SAndroid Build Coastguard Worker    Instead we get the more natural expected result:
1175*b9df5ad1SAndroid Build Coastguard Worker
1176*b9df5ad1SAndroid Build Coastguard Worker      <!-- Good Output -->
1177*b9df5ad1SAndroid Build Coastguard Worker      <p>foo
1178*b9df5ad1SAndroid Build Coastguard Worker      bar
1179*b9df5ad1SAndroid Build Coastguard Worker      bar</p>
1180*b9df5ad1SAndroid Build Coastguard Worker
1181*b9df5ad1SAndroid Build Coastguard Worker    """
1182*b9df5ad1SAndroid Build Coastguard Worker    text = dedent(text)
1183*b9df5ad1SAndroid Build Coastguard Worker
1184*b9df5ad1SAndroid Build Coastguard Worker    # full list of extensions at http://pythonhosted.org/Markdown/extensions/
1185*b9df5ad1SAndroid Build Coastguard Worker    md_extensions = ['tables'] if table_ext else []# make <table> with ASCII |_| tables
1186*b9df5ad1SAndroid Build Coastguard Worker    # render with markdown
1187*b9df5ad1SAndroid Build Coastguard Worker    text = markdown.markdown(text, extensions=md_extensions)
1188*b9df5ad1SAndroid Build Coastguard Worker
1189*b9df5ad1SAndroid Build Coastguard Worker    # prepend a prefix to each <img src="foo"> -> <img src="${prefix}foo">
1190*b9df5ad1SAndroid Build Coastguard Worker    text = re.sub(r'src="([^"]*)"', 'src="' + img_src_prefix + r'\1"', text)
1191*b9df5ad1SAndroid Build Coastguard Worker    return text
1192*b9df5ad1SAndroid Build Coastguard Worker
1193*b9df5ad1SAndroid Build Coastguard Workerdef filter_tags(text, metadata, filter_function, summary_function = None):
1194*b9df5ad1SAndroid Build Coastguard Worker    """
1195*b9df5ad1SAndroid Build Coastguard Worker    Find all references to tags in the form outer_namespace.xxx.yyy[.zzz] in
1196*b9df5ad1SAndroid Build Coastguard Worker    the provided text, and pass them through filter_function and summary_function.
1197*b9df5ad1SAndroid Build Coastguard Worker
1198*b9df5ad1SAndroid Build Coastguard Worker    Used to linkify entry names in HMTL, javadoc output.
1199*b9df5ad1SAndroid Build Coastguard Worker
1200*b9df5ad1SAndroid Build Coastguard Worker    Args:
1201*b9df5ad1SAndroid Build Coastguard Worker      text: A string representing a block of text destined for output
1202*b9df5ad1SAndroid Build Coastguard Worker      metadata: A Metadata instance, the root of the metadata properties tree
1203*b9df5ad1SAndroid Build Coastguard Worker      filter_function: A Node->string function to apply to each node
1204*b9df5ad1SAndroid Build Coastguard Worker        when found in text; the string returned replaces the tag name in text.
1205*b9df5ad1SAndroid Build Coastguard Worker      summary_function: A Node list->string function that is provided the list of
1206*b9df5ad1SAndroid Build Coastguard Worker        unique tag nodes found in text, and which must return a string that is
1207*b9df5ad1SAndroid Build Coastguard Worker        then appended to the end of the text. The list is sorted alphabetically
1208*b9df5ad1SAndroid Build Coastguard Worker        by node name.
1209*b9df5ad1SAndroid Build Coastguard Worker    """
1210*b9df5ad1SAndroid Build Coastguard Worker
1211*b9df5ad1SAndroid Build Coastguard Worker    tag_set = set()
1212*b9df5ad1SAndroid Build Coastguard Worker    def name_match(name):
1213*b9df5ad1SAndroid Build Coastguard Worker      return lambda node: node.name == name
1214*b9df5ad1SAndroid Build Coastguard Worker
1215*b9df5ad1SAndroid Build Coastguard Worker    # Match outer_namespace.x.y or outer_namespace.x.y.z, making sure
1216*b9df5ad1SAndroid Build Coastguard Worker    # to grab .z and not just outer_namespace.x.y.  (sloppy, but since we
1217*b9df5ad1SAndroid Build Coastguard Worker    # check for validity, a few false positives don't hurt).
1218*b9df5ad1SAndroid Build Coastguard Worker    # Try to ignore items of the form {@link <outer_namespace>...
1219*b9df5ad1SAndroid Build Coastguard Worker    for outer_namespace in metadata.outer_namespaces:
1220*b9df5ad1SAndroid Build Coastguard Worker
1221*b9df5ad1SAndroid Build Coastguard Worker      tag_match = r"(?<!\{@link\s)" + outer_namespace.name + \
1222*b9df5ad1SAndroid Build Coastguard Worker        r"\.([a-zA-Z0-9\n]+)\.([a-zA-Z0-9\n]+)(\.[a-zA-Z0-9\n]+)?([/]?)"
1223*b9df5ad1SAndroid Build Coastguard Worker
1224*b9df5ad1SAndroid Build Coastguard Worker      def filter_sub(match):
1225*b9df5ad1SAndroid Build Coastguard Worker        whole_match = match.group(0)
1226*b9df5ad1SAndroid Build Coastguard Worker        section1 = match.group(1)
1227*b9df5ad1SAndroid Build Coastguard Worker        section2 = match.group(2)
1228*b9df5ad1SAndroid Build Coastguard Worker        section3 = match.group(3)
1229*b9df5ad1SAndroid Build Coastguard Worker        end_slash = match.group(4)
1230*b9df5ad1SAndroid Build Coastguard Worker
1231*b9df5ad1SAndroid Build Coastguard Worker        # Don't linkify things ending in slash (urls, for example)
1232*b9df5ad1SAndroid Build Coastguard Worker        if end_slash:
1233*b9df5ad1SAndroid Build Coastguard Worker          return whole_match
1234*b9df5ad1SAndroid Build Coastguard Worker
1235*b9df5ad1SAndroid Build Coastguard Worker        candidate = ""
1236*b9df5ad1SAndroid Build Coastguard Worker
1237*b9df5ad1SAndroid Build Coastguard Worker        # First try a two-level match
1238*b9df5ad1SAndroid Build Coastguard Worker        candidate2 = "%s.%s.%s" % (outer_namespace.name, section1, section2)
1239*b9df5ad1SAndroid Build Coastguard Worker        got_two_level = False
1240*b9df5ad1SAndroid Build Coastguard Worker
1241*b9df5ad1SAndroid Build Coastguard Worker        node = metadata.find_first(name_match(candidate2.replace('\n','')))
1242*b9df5ad1SAndroid Build Coastguard Worker        if not node and '\n' in section2:
1243*b9df5ad1SAndroid Build Coastguard Worker          # Linefeeds are ambiguous - was the intent to add a space,
1244*b9df5ad1SAndroid Build Coastguard Worker          # or continue a lengthy name? Try the former now.
1245*b9df5ad1SAndroid Build Coastguard Worker          candidate2b = "%s.%s.%s" % (outer_namespace.name, section1, section2[:section2.find('\n')])
1246*b9df5ad1SAndroid Build Coastguard Worker          node = metadata.find_first(name_match(candidate2b))
1247*b9df5ad1SAndroid Build Coastguard Worker          if node:
1248*b9df5ad1SAndroid Build Coastguard Worker            candidate2 = candidate2b
1249*b9df5ad1SAndroid Build Coastguard Worker
1250*b9df5ad1SAndroid Build Coastguard Worker        if node:
1251*b9df5ad1SAndroid Build Coastguard Worker          # Have two-level match
1252*b9df5ad1SAndroid Build Coastguard Worker          got_two_level = True
1253*b9df5ad1SAndroid Build Coastguard Worker          candidate = candidate2
1254*b9df5ad1SAndroid Build Coastguard Worker        elif section3:
1255*b9df5ad1SAndroid Build Coastguard Worker          # Try three-level match
1256*b9df5ad1SAndroid Build Coastguard Worker          candidate3 = "%s%s" % (candidate2, section3)
1257*b9df5ad1SAndroid Build Coastguard Worker          node = metadata.find_first(name_match(candidate3.replace('\n','')))
1258*b9df5ad1SAndroid Build Coastguard Worker
1259*b9df5ad1SAndroid Build Coastguard Worker          if not node and '\n' in section3:
1260*b9df5ad1SAndroid Build Coastguard Worker            # Linefeeds are ambiguous - was the intent to add a space,
1261*b9df5ad1SAndroid Build Coastguard Worker            # or continue a lengthy name? Try the former now.
1262*b9df5ad1SAndroid Build Coastguard Worker            candidate3b = "%s%s" % (candidate2, section3[:section3.find('\n')])
1263*b9df5ad1SAndroid Build Coastguard Worker            node = metadata.find_first(name_match(candidate3b))
1264*b9df5ad1SAndroid Build Coastguard Worker            if node:
1265*b9df5ad1SAndroid Build Coastguard Worker              candidate3 = candidate3b
1266*b9df5ad1SAndroid Build Coastguard Worker
1267*b9df5ad1SAndroid Build Coastguard Worker          if node:
1268*b9df5ad1SAndroid Build Coastguard Worker            # Have 3-level match
1269*b9df5ad1SAndroid Build Coastguard Worker            candidate = candidate3
1270*b9df5ad1SAndroid Build Coastguard Worker
1271*b9df5ad1SAndroid Build Coastguard Worker        # Replace match with crossref or complain if a likely match couldn't be matched
1272*b9df5ad1SAndroid Build Coastguard Worker
1273*b9df5ad1SAndroid Build Coastguard Worker        if node:
1274*b9df5ad1SAndroid Build Coastguard Worker          tag_set.add(node)
1275*b9df5ad1SAndroid Build Coastguard Worker          return whole_match.replace(candidate,filter_function(node))
1276*b9df5ad1SAndroid Build Coastguard Worker        else:
1277*b9df5ad1SAndroid Build Coastguard Worker          print("  WARNING: Could not crossref likely reference {%s}" % (match.group(0)),
1278*b9df5ad1SAndroid Build Coastguard Worker                file=sys.stderr)
1279*b9df5ad1SAndroid Build Coastguard Worker          return whole_match
1280*b9df5ad1SAndroid Build Coastguard Worker
1281*b9df5ad1SAndroid Build Coastguard Worker      text = re.sub(tag_match, filter_sub, text)
1282*b9df5ad1SAndroid Build Coastguard Worker
1283*b9df5ad1SAndroid Build Coastguard Worker    if summary_function is not None:
1284*b9df5ad1SAndroid Build Coastguard Worker      return text + summary_function(sorted(tag_set, key=lambda x: x.name))
1285*b9df5ad1SAndroid Build Coastguard Worker    else:
1286*b9df5ad1SAndroid Build Coastguard Worker      return text
1287*b9df5ad1SAndroid Build Coastguard Worker
1288*b9df5ad1SAndroid Build Coastguard Workerdef ndk_replace_tag_wildcards(text, metadata):
1289*b9df5ad1SAndroid Build Coastguard Worker    """
1290*b9df5ad1SAndroid Build Coastguard Worker    Find all references to tags in the form android.xxx.* or android.xxx.yyy.*
1291*b9df5ad1SAndroid Build Coastguard Worker    in the provided text, and replace them by NDK format of "ACAMERA_XXX_*" or
1292*b9df5ad1SAndroid Build Coastguard Worker    "ACAMERA_XXX_YYY_*"
1293*b9df5ad1SAndroid Build Coastguard Worker
1294*b9df5ad1SAndroid Build Coastguard Worker    Args:
1295*b9df5ad1SAndroid Build Coastguard Worker      text: A string representing a block of text destined for output
1296*b9df5ad1SAndroid Build Coastguard Worker      metadata: A Metadata instance, the root of the metadata properties tree
1297*b9df5ad1SAndroid Build Coastguard Worker    """
1298*b9df5ad1SAndroid Build Coastguard Worker    tag_match = r"android\.([a-zA-Z0-9\n]+)\.\*"
1299*b9df5ad1SAndroid Build Coastguard Worker    tag_match_2 = r"android\.([a-zA-Z0-9\n]+)\.([a-zA-Z0-9\n]+)\*"
1300*b9df5ad1SAndroid Build Coastguard Worker
1301*b9df5ad1SAndroid Build Coastguard Worker    def filter_sub(match):
1302*b9df5ad1SAndroid Build Coastguard Worker      return "ACAMERA_" + match.group(1).upper() + "_*"
1303*b9df5ad1SAndroid Build Coastguard Worker    def filter_sub_2(match):
1304*b9df5ad1SAndroid Build Coastguard Worker      return "ACAMERA_" + match.group(1).upper() + match.group(2).upper() + "_*"
1305*b9df5ad1SAndroid Build Coastguard Worker
1306*b9df5ad1SAndroid Build Coastguard Worker    text = re.sub(tag_match, filter_sub, text)
1307*b9df5ad1SAndroid Build Coastguard Worker    text = re.sub(tag_match_2, filter_sub_2, text)
1308*b9df5ad1SAndroid Build Coastguard Worker    return text
1309*b9df5ad1SAndroid Build Coastguard Worker
1310*b9df5ad1SAndroid Build Coastguard Workerdef filter_links(text, filter_function, summary_function = None):
1311*b9df5ad1SAndroid Build Coastguard Worker    """
1312*b9df5ad1SAndroid Build Coastguard Worker    Find all references to tags in the form {@link xxx#yyy [zzz]} in the
1313*b9df5ad1SAndroid Build Coastguard Worker    provided text, and pass them through filter_function and
1314*b9df5ad1SAndroid Build Coastguard Worker    summary_function.
1315*b9df5ad1SAndroid Build Coastguard Worker
1316*b9df5ad1SAndroid Build Coastguard Worker    Used to linkify documentation cross-references in HMTL, javadoc output.
1317*b9df5ad1SAndroid Build Coastguard Worker
1318*b9df5ad1SAndroid Build Coastguard Worker    Args:
1319*b9df5ad1SAndroid Build Coastguard Worker      text: A string representing a block of text destined for output
1320*b9df5ad1SAndroid Build Coastguard Worker      metadata: A Metadata instance, the root of the metadata properties tree
1321*b9df5ad1SAndroid Build Coastguard Worker      filter_function: A (string, string)->string function to apply to each 'xxx#yyy',
1322*b9df5ad1SAndroid Build Coastguard Worker        zzz pair when found in text; the string returned replaces the tag name in text.
1323*b9df5ad1SAndroid Build Coastguard Worker      summary_function: A string list->string function that is provided the list of
1324*b9df5ad1SAndroid Build Coastguard Worker        unique targets found in text, and which must return a string that is
1325*b9df5ad1SAndroid Build Coastguard Worker        then appended to the end of the text. The list is sorted alphabetically
1326*b9df5ad1SAndroid Build Coastguard Worker        by node name.
1327*b9df5ad1SAndroid Build Coastguard Worker
1328*b9df5ad1SAndroid Build Coastguard Worker    """
1329*b9df5ad1SAndroid Build Coastguard Worker
1330*b9df5ad1SAndroid Build Coastguard Worker    target_set = set()
1331*b9df5ad1SAndroid Build Coastguard Worker    def name_match(name):
1332*b9df5ad1SAndroid Build Coastguard Worker      return lambda node: node.name == name
1333*b9df5ad1SAndroid Build Coastguard Worker
1334*b9df5ad1SAndroid Build Coastguard Worker    tag_match = r"\{@link\s+([^\s\}\|]+)(?:\|([^\s\}]+))*([^\}]*)\}"
1335*b9df5ad1SAndroid Build Coastguard Worker
1336*b9df5ad1SAndroid Build Coastguard Worker    def filter_sub(match):
1337*b9df5ad1SAndroid Build Coastguard Worker      whole_match = match.group(0)
1338*b9df5ad1SAndroid Build Coastguard Worker      target = match.group(1)
1339*b9df5ad1SAndroid Build Coastguard Worker      target_ndk = match.group(2)
1340*b9df5ad1SAndroid Build Coastguard Worker      shortname = match.group(3).strip()
1341*b9df5ad1SAndroid Build Coastguard Worker
1342*b9df5ad1SAndroid Build Coastguard Worker      #print("Found link '%s' ndk '%s' as '%s' -> '%s'" % (target, target_ndk, shortname, filter_function(target, target_ndk, shortname)))
1343*b9df5ad1SAndroid Build Coastguard Worker
1344*b9df5ad1SAndroid Build Coastguard Worker      # Replace match with crossref
1345*b9df5ad1SAndroid Build Coastguard Worker      target_set.add(target)
1346*b9df5ad1SAndroid Build Coastguard Worker      return filter_function(target, target_ndk, shortname)
1347*b9df5ad1SAndroid Build Coastguard Worker
1348*b9df5ad1SAndroid Build Coastguard Worker    text = re.sub(tag_match, filter_sub, text)
1349*b9df5ad1SAndroid Build Coastguard Worker
1350*b9df5ad1SAndroid Build Coastguard Worker    if summary_function is not None:
1351*b9df5ad1SAndroid Build Coastguard Worker      return text + summary_function(sorted(target_set))
1352*b9df5ad1SAndroid Build Coastguard Worker    else:
1353*b9df5ad1SAndroid Build Coastguard Worker      return text
1354*b9df5ad1SAndroid Build Coastguard Worker
1355*b9df5ad1SAndroid Build Coastguard Workerdef any_visible(section, kind_name, visibilities):
1356*b9df5ad1SAndroid Build Coastguard Worker  """
1357*b9df5ad1SAndroid Build Coastguard Worker  Determine if entries in this section have an applied visibility that's in
1358*b9df5ad1SAndroid Build Coastguard Worker  the list of given visibilities.
1359*b9df5ad1SAndroid Build Coastguard Worker
1360*b9df5ad1SAndroid Build Coastguard Worker  Args:
1361*b9df5ad1SAndroid Build Coastguard Worker    section: A section of metadata
1362*b9df5ad1SAndroid Build Coastguard Worker    kind_name: A name of the kind, i.e. 'dynamic' or 'static' or 'controls'
1363*b9df5ad1SAndroid Build Coastguard Worker    visibilities: An iterable of visibilities to match against
1364*b9df5ad1SAndroid Build Coastguard Worker
1365*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1366*b9df5ad1SAndroid Build Coastguard Worker    True if the section has any entries with any of the given visibilities. False otherwise.
1367*b9df5ad1SAndroid Build Coastguard Worker  """
1368*b9df5ad1SAndroid Build Coastguard Worker
1369*b9df5ad1SAndroid Build Coastguard Worker  for inner_namespace in get_children_by_filtering_kind(section, kind_name,
1370*b9df5ad1SAndroid Build Coastguard Worker                                                        'namespaces'):
1371*b9df5ad1SAndroid Build Coastguard Worker    if any(filter_visibility(inner_namespace.merged_entries, visibilities)):
1372*b9df5ad1SAndroid Build Coastguard Worker      return True
1373*b9df5ad1SAndroid Build Coastguard Worker
1374*b9df5ad1SAndroid Build Coastguard Worker  return any(filter_visibility(get_children_by_filtering_kind(section, kind_name,
1375*b9df5ad1SAndroid Build Coastguard Worker                                                              'merged_entries'),
1376*b9df5ad1SAndroid Build Coastguard Worker                               visibilities))
1377*b9df5ad1SAndroid Build Coastguard Worker
1378*b9df5ad1SAndroid Build Coastguard Workerdef filter_visibility(entries, visibilities):
1379*b9df5ad1SAndroid Build Coastguard Worker  """
1380*b9df5ad1SAndroid Build Coastguard Worker  Remove entries whose applied visibility is not in the supplied visibilities.
1381*b9df5ad1SAndroid Build Coastguard Worker
1382*b9df5ad1SAndroid Build Coastguard Worker  Args:
1383*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1384*b9df5ad1SAndroid Build Coastguard Worker    visibilities: An iterable of visibilities to filter against
1385*b9df5ad1SAndroid Build Coastguard Worker
1386*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1387*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1388*b9df5ad1SAndroid Build Coastguard Worker  """
1389*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if e.applied_visibility in visibilities)
1390*b9df5ad1SAndroid Build Coastguard Worker
1391*b9df5ad1SAndroid Build Coastguard Workerdef is_not_hal_visible(e):
1392*b9df5ad1SAndroid Build Coastguard Worker  """
1393*b9df5ad1SAndroid Build Coastguard Worker  Determine that the entry being passed in is not visible to HAL.
1394*b9df5ad1SAndroid Build Coastguard Worker
1395*b9df5ad1SAndroid Build Coastguard Worker  Args:
1396*b9df5ad1SAndroid Build Coastguard Worker    e: An entry node
1397*b9df5ad1SAndroid Build Coastguard Worker
1398*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1399*b9df5ad1SAndroid Build Coastguard Worker    True if the entry is not visible to HAL
1400*b9df5ad1SAndroid Build Coastguard Worker  """
1401*b9df5ad1SAndroid Build Coastguard Worker  return (e.visibility == 'fwk_only' or
1402*b9df5ad1SAndroid Build Coastguard Worker          e.visibility == 'fwk_java_public' or
1403*b9df5ad1SAndroid Build Coastguard Worker          e.visibility == 'fwk_public' or
1404*b9df5ad1SAndroid Build Coastguard Worker          e.visibility == 'fwk_system_public' or
1405*b9df5ad1SAndroid Build Coastguard Worker          e.visibility == 'fwk_ndk_public' or
1406*b9df5ad1SAndroid Build Coastguard Worker          e.visibility == 'extension')
1407*b9df5ad1SAndroid Build Coastguard Worker
1408*b9df5ad1SAndroid Build Coastguard Workerdef remove_hal_non_visible(entries):
1409*b9df5ad1SAndroid Build Coastguard Worker  """
1410*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries by removing those that are not HAL visible:
1411*b9df5ad1SAndroid Build Coastguard Worker  synthetic, fwk_only, extension, fwk_java_public, fwk_system_public, fwk_ndk_public,
1412*b9df5ad1SAndroid Build Coastguard Worker  or fwk_public.
1413*b9df5ad1SAndroid Build Coastguard Worker
1414*b9df5ad1SAndroid Build Coastguard Worker  Args:
1415*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1416*b9df5ad1SAndroid Build Coastguard Worker
1417*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1418*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1419*b9df5ad1SAndroid Build Coastguard Worker  """
1420*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if not (e.synthetic or is_not_hal_visible(e)))
1421*b9df5ad1SAndroid Build Coastguard Worker
1422*b9df5ad1SAndroid Build Coastguard Workerdef remove_ndk_non_visible(entries):
1423*b9df5ad1SAndroid Build Coastguard Worker  """
1424*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries by removing those that are not NDK visible:
1425*b9df5ad1SAndroid Build Coastguard Worker  synthetic, fwk_only, extension, or fwk_java_public.
1426*b9df5ad1SAndroid Build Coastguard Worker
1427*b9df5ad1SAndroid Build Coastguard Worker  Args:
1428*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1429*b9df5ad1SAndroid Build Coastguard Worker
1430*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1431*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1432*b9df5ad1SAndroid Build Coastguard Worker  """
1433*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if not (e.synthetic or e.visibility == 'fwk_only'
1434*b9df5ad1SAndroid Build Coastguard Worker                                     or e.visibility == 'fwk_java_public' or
1435*b9df5ad1SAndroid Build Coastguard Worker                                     e.visibility == 'extension'))
1436*b9df5ad1SAndroid Build Coastguard Worker
1437*b9df5ad1SAndroid Build Coastguard Worker"""
1438*b9df5ad1SAndroid Build Coastguard Worker  Return the vndk version for a given hal minor version. The major version is assumed to be 3
1439*b9df5ad1SAndroid Build Coastguard Worker
1440*b9df5ad1SAndroid Build Coastguard Worker  Args:
1441*b9df5ad1SAndroid Build Coastguard Worker    hal_minor_version : minor version to retrieve the vndk version for
1442*b9df5ad1SAndroid Build Coastguard Worker
1443*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1444*b9df5ad1SAndroid Build Coastguard Worker    int representing the vndk version
1445*b9df5ad1SAndroid Build Coastguard Worker  """
1446*b9df5ad1SAndroid Build Coastguard Workerdef get_vndk_version(hal_minor_version):
1447*b9df5ad1SAndroid Build Coastguard Worker  if hal_minor_version <= FRAMEWORK_CAMERA_VNDK_HAL_MINOR_VERSION:
1448*b9df5ad1SAndroid Build Coastguard Worker    return 0
1449*b9df5ad1SAndroid Build Coastguard Worker  return hal_minor_version - FRAMEWORK_CAMERA_VNDK_HAL_MINOR_VERSION \
1450*b9df5ad1SAndroid Build Coastguard Worker        + FRAMEWORK_CAMERA_VNDK_STARTING_VERSION
1451*b9df5ad1SAndroid Build Coastguard Worker
1452*b9df5ad1SAndroid Build Coastguard Worker"""
1453*b9df5ad1SAndroid Build Coastguard Worker  Returns an api level -> dict of metadata tags corresponding to the api level
1454*b9df5ad1SAndroid Build Coastguard Worker
1455*b9df5ad1SAndroid Build Coastguard Worker  Args:
1456*b9df5ad1SAndroid Build Coastguard Worker    sections : metadata sections to create the mapping for
1457*b9df5ad1SAndroid Build Coastguard Worker    metadata: the metadata structure to be used to create the mapping
1458*b9df5ad1SAndroid Build Coastguard Worker    kind : kind of entries to create a mapping for : 'static' or 'dynamic'
1459*b9df5ad1SAndroid Build Coastguard Worker
1460*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1461*b9df5ad1SAndroid Build Coastguard Worker    A dictionary mapping api level to a dictionary of metadata tags for the particular key (api level)
1462*b9df5ad1SAndroid Build Coastguard Worker  """
1463*b9df5ad1SAndroid Build Coastguard Workerdef get_api_level_to_keys(sections, metadata, kind):
1464*b9df5ad1SAndroid Build Coastguard Worker  api_level_to_keys = {}
1465*b9df5ad1SAndroid Build Coastguard Worker  for sec in sections:
1466*b9df5ad1SAndroid Build Coastguard Worker    for idx,entry in enumerate(remove_synthetic(find_unique_entries(sec))):
1467*b9df5ad1SAndroid Build Coastguard Worker      if entry._hal_minor_version > FRAMEWORK_CAMERA_VNDK_HAL_MINOR_VERSION and \
1468*b9df5ad1SAndroid Build Coastguard Worker          metadata.is_entry_this_kind(entry, kind):
1469*b9df5ad1SAndroid Build Coastguard Worker        api_level = get_vndk_version(entry._hal_minor_version)
1470*b9df5ad1SAndroid Build Coastguard Worker        try:
1471*b9df5ad1SAndroid Build Coastguard Worker          api_level_to_keys[api_level].add(entry.name)
1472*b9df5ad1SAndroid Build Coastguard Worker        except KeyError:
1473*b9df5ad1SAndroid Build Coastguard Worker          api_level_to_keys[api_level] = {entry.name}
1474*b9df5ad1SAndroid Build Coastguard Worker  #Insert the keys in sorted order since dicts in python (< 3.7, even OrderedDicts don't actually
1475*b9df5ad1SAndroid Build Coastguard Worker  # sort keys)
1476*b9df5ad1SAndroid Build Coastguard Worker  api_level_to_keys_ordered = OrderedDict()
1477*b9df5ad1SAndroid Build Coastguard Worker  for api_level_ordered in sorted(api_level_to_keys.keys()):
1478*b9df5ad1SAndroid Build Coastguard Worker    api_level_to_keys_ordered[api_level_ordered] = sorted(api_level_to_keys[api_level_ordered])
1479*b9df5ad1SAndroid Build Coastguard Worker  return api_level_to_keys_ordered
1480*b9df5ad1SAndroid Build Coastguard Worker
1481*b9df5ad1SAndroid Build Coastguard Worker
1482*b9df5ad1SAndroid Build Coastguard Workerdef get_api_level_to_session_characteristic_keys(sections):
1483*b9df5ad1SAndroid Build Coastguard Worker  """
1484*b9df5ad1SAndroid Build Coastguard Worker  Returns a mapping of api_level -> list session characteristics tag keys where api_level
1485*b9df5ad1SAndroid Build Coastguard Worker  is the level at which they became a part of getSessionCharacteristics call.
1486*b9df5ad1SAndroid Build Coastguard Worker
1487*b9df5ad1SAndroid Build Coastguard Worker  Args:
1488*b9df5ad1SAndroid Build Coastguard Worker    sections : metadata sections to create the mapping for
1489*b9df5ad1SAndroid Build Coastguard Worker
1490*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1491*b9df5ad1SAndroid Build Coastguard Worker    A dictionary mapping api level to a list of metadata tags.
1492*b9df5ad1SAndroid Build Coastguard Worker  """
1493*b9df5ad1SAndroid Build Coastguard Worker  api_level_to_keys = defaultdict(list)
1494*b9df5ad1SAndroid Build Coastguard Worker  for sec in sections:
1495*b9df5ad1SAndroid Build Coastguard Worker    for entry in remove_synthetic(find_unique_entries(sec)):
1496*b9df5ad1SAndroid Build Coastguard Worker      if entry.session_characteristics_key_since is None:
1497*b9df5ad1SAndroid Build Coastguard Worker        continue
1498*b9df5ad1SAndroid Build Coastguard Worker
1499*b9df5ad1SAndroid Build Coastguard Worker      api_level = entry.session_characteristics_key_since
1500*b9df5ad1SAndroid Build Coastguard Worker      api_level_to_keys[api_level].append(entry.name)
1501*b9df5ad1SAndroid Build Coastguard Worker
1502*b9df5ad1SAndroid Build Coastguard Worker  # sort dictionary on its key (api_level)
1503*b9df5ad1SAndroid Build Coastguard Worker  api_level_to_keys = OrderedDict(sorted(api_level_to_keys.items(), key=itemgetter(0)))
1504*b9df5ad1SAndroid Build Coastguard Worker  # sort the keys for each api_level
1505*b9df5ad1SAndroid Build Coastguard Worker  for api_level, keys in api_level_to_keys.items():
1506*b9df5ad1SAndroid Build Coastguard Worker    api_level_to_keys[api_level] = sorted(keys)
1507*b9df5ad1SAndroid Build Coastguard Worker
1508*b9df5ad1SAndroid Build Coastguard Worker  return api_level_to_keys
1509*b9df5ad1SAndroid Build Coastguard Worker
1510*b9df5ad1SAndroid Build Coastguard Worker
1511*b9df5ad1SAndroid Build Coastguard Workerdef remove_synthetic(entries):
1512*b9df5ad1SAndroid Build Coastguard Worker  """
1513*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries by removing those that are synthetic.
1514*b9df5ad1SAndroid Build Coastguard Worker
1515*b9df5ad1SAndroid Build Coastguard Worker  Args:
1516*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1517*b9df5ad1SAndroid Build Coastguard Worker
1518*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1519*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1520*b9df5ad1SAndroid Build Coastguard Worker  """
1521*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if not e.synthetic)
1522*b9df5ad1SAndroid Build Coastguard Worker
1523*b9df5ad1SAndroid Build Coastguard Workerdef filter_added_in_hal_version(entries, hal_major_version, hal_minor_version):
1524*b9df5ad1SAndroid Build Coastguard Worker  """
1525*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries to those added in the given HIDL HAL version
1526*b9df5ad1SAndroid Build Coastguard Worker
1527*b9df5ad1SAndroid Build Coastguard Worker  Args:
1528*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1529*b9df5ad1SAndroid Build Coastguard Worker    hal_major_version: Major HIDL version to filter for
1530*b9df5ad1SAndroid Build Coastguard Worker    hal_minor_version: Minor HIDL version to filter for
1531*b9df5ad1SAndroid Build Coastguard Worker
1532*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1533*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1534*b9df5ad1SAndroid Build Coastguard Worker  """
1535*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if e.hal_major_version == hal_major_version and e.hal_minor_version == hal_minor_version)
1536*b9df5ad1SAndroid Build Coastguard Worker
1537*b9df5ad1SAndroid Build Coastguard Workerdef filter_has_enum_values_added_in_hal_version(entries, hal_major_version, hal_minor_version):
1538*b9df5ad1SAndroid Build Coastguard Worker  """
1539*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries to those that have a new enum value added in the given HIDL HAL version
1540*b9df5ad1SAndroid Build Coastguard Worker
1541*b9df5ad1SAndroid Build Coastguard Worker  Args:
1542*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1543*b9df5ad1SAndroid Build Coastguard Worker    hal_major_version: Major HIDL version to filter for
1544*b9df5ad1SAndroid Build Coastguard Worker    hal_minor_version: Minor HIDL version to filter for
1545*b9df5ad1SAndroid Build Coastguard Worker
1546*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1547*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1548*b9df5ad1SAndroid Build Coastguard Worker  """
1549*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if e.has_new_values_added_in_hal_version(hal_major_version, hal_minor_version))
1550*b9df5ad1SAndroid Build Coastguard Worker
1551*b9df5ad1SAndroid Build Coastguard Workerdef permission_needed_count(root):
1552*b9df5ad1SAndroid Build Coastguard Worker  """
1553*b9df5ad1SAndroid Build Coastguard Worker  Return the number entries that need camera permission.
1554*b9df5ad1SAndroid Build Coastguard Worker
1555*b9df5ad1SAndroid Build Coastguard Worker  Args:
1556*b9df5ad1SAndroid Build Coastguard Worker    root: a Metadata instance
1557*b9df5ad1SAndroid Build Coastguard Worker
1558*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1559*b9df5ad1SAndroid Build Coastguard Worker    The number of entires that need camera permission.
1560*b9df5ad1SAndroid Build Coastguard Worker
1561*b9df5ad1SAndroid Build Coastguard Worker  """
1562*b9df5ad1SAndroid Build Coastguard Worker  ret = 0
1563*b9df5ad1SAndroid Build Coastguard Worker  for sec in find_all_sections(root):
1564*b9df5ad1SAndroid Build Coastguard Worker      ret += len(list(filter_has_permission_needed(remove_hal_non_visible(find_unique_entries(sec)))))
1565*b9df5ad1SAndroid Build Coastguard Worker
1566*b9df5ad1SAndroid Build Coastguard Worker  return ret
1567*b9df5ad1SAndroid Build Coastguard Worker
1568*b9df5ad1SAndroid Build Coastguard Workerdef filter_has_permission_needed(entries):
1569*b9df5ad1SAndroid Build Coastguard Worker  """
1570*b9df5ad1SAndroid Build Coastguard Worker    Filter the given entries by removing those that don't need camera permission.
1571*b9df5ad1SAndroid Build Coastguard Worker
1572*b9df5ad1SAndroid Build Coastguard Worker    Args:
1573*b9df5ad1SAndroid Build Coastguard Worker      entries: An iterable of Entry nodes
1574*b9df5ad1SAndroid Build Coastguard Worker
1575*b9df5ad1SAndroid Build Coastguard Worker    Yields:
1576*b9df5ad1SAndroid Build Coastguard Worker      An iterable of Entry nodes
1577*b9df5ad1SAndroid Build Coastguard Worker  """
1578*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if e.permission_needed == 'true')
1579*b9df5ad1SAndroid Build Coastguard Worker
1580*b9df5ad1SAndroid Build Coastguard Workerdef filter_ndk_visible(entries):
1581*b9df5ad1SAndroid Build Coastguard Worker  """
1582*b9df5ad1SAndroid Build Coastguard Worker  Filter the given entries by removing those that are not NDK visible.
1583*b9df5ad1SAndroid Build Coastguard Worker
1584*b9df5ad1SAndroid Build Coastguard Worker  Args:
1585*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable of Entry nodes
1586*b9df5ad1SAndroid Build Coastguard Worker
1587*b9df5ad1SAndroid Build Coastguard Worker  Yields:
1588*b9df5ad1SAndroid Build Coastguard Worker    An iterable of Entry nodes
1589*b9df5ad1SAndroid Build Coastguard Worker  """
1590*b9df5ad1SAndroid Build Coastguard Worker  return (e for e in entries if e.applied_ndk_visible == 'true')
1591*b9df5ad1SAndroid Build Coastguard Worker
1592*b9df5ad1SAndroid Build Coastguard Workerdef wbr(text):
1593*b9df5ad1SAndroid Build Coastguard Worker  """
1594*b9df5ad1SAndroid Build Coastguard Worker  Insert word break hints for the browser in the form of <wbr> HTML tags.
1595*b9df5ad1SAndroid Build Coastguard Worker
1596*b9df5ad1SAndroid Build Coastguard Worker  Word breaks are inserted inside an HTML node only, so the nodes themselves
1597*b9df5ad1SAndroid Build Coastguard Worker  will not be changed. Attributes are also left unchanged.
1598*b9df5ad1SAndroid Build Coastguard Worker
1599*b9df5ad1SAndroid Build Coastguard Worker  The following rules apply to insert word breaks:
1600*b9df5ad1SAndroid Build Coastguard Worker  - For characters in [ '.', '/', '_' ]
1601*b9df5ad1SAndroid Build Coastguard Worker  - For uppercase letters inside a multi-word X.Y.Z (at least 3 parts)
1602*b9df5ad1SAndroid Build Coastguard Worker
1603*b9df5ad1SAndroid Build Coastguard Worker  Args:
1604*b9df5ad1SAndroid Build Coastguard Worker    text: A string of text containing HTML content.
1605*b9df5ad1SAndroid Build Coastguard Worker
1606*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1607*b9df5ad1SAndroid Build Coastguard Worker    A string with <wbr> inserted by the above rules.
1608*b9df5ad1SAndroid Build Coastguard Worker  """
1609*b9df5ad1SAndroid Build Coastguard Worker  SPLIT_CHARS_LIST = ['.', '_', '/']
1610*b9df5ad1SAndroid Build Coastguard Worker  SPLIT_CHARS = r'([.|/|_/,]+)' # split by these characters
1611*b9df5ad1SAndroid Build Coastguard Worker  CAP_LETTER_MIN = 3 # at least 3 components split by above chars, i.e. x.y.z
1612*b9df5ad1SAndroid Build Coastguard Worker  def wbr_filter(text):
1613*b9df5ad1SAndroid Build Coastguard Worker      new_txt = text
1614*b9df5ad1SAndroid Build Coastguard Worker
1615*b9df5ad1SAndroid Build Coastguard Worker      # for johnyOrange.appleCider.redGuardian also insert wbr before the caps
1616*b9df5ad1SAndroid Build Coastguard Worker      # => johny<wbr>Orange.apple<wbr>Cider.red<wbr>Guardian
1617*b9df5ad1SAndroid Build Coastguard Worker      for words in text.split(" "):
1618*b9df5ad1SAndroid Build Coastguard Worker        for char in SPLIT_CHARS_LIST:
1619*b9df5ad1SAndroid Build Coastguard Worker          # match at least x.y.z, don't match x or x.y
1620*b9df5ad1SAndroid Build Coastguard Worker          if len(words.split(char)) >= CAP_LETTER_MIN:
1621*b9df5ad1SAndroid Build Coastguard Worker            new_word = re.sub(r"([a-z])([A-Z])", r"\1<wbr>\2", words)
1622*b9df5ad1SAndroid Build Coastguard Worker            new_txt = new_txt.replace(words, new_word)
1623*b9df5ad1SAndroid Build Coastguard Worker
1624*b9df5ad1SAndroid Build Coastguard Worker      # e.g. X/Y/Z -> X/<wbr>Y/<wbr>/Z. also for X.Y.Z, X_Y_Z.
1625*b9df5ad1SAndroid Build Coastguard Worker      new_txt = re.sub(SPLIT_CHARS, r"\1<wbr>", new_txt)
1626*b9df5ad1SAndroid Build Coastguard Worker
1627*b9df5ad1SAndroid Build Coastguard Worker      return new_txt
1628*b9df5ad1SAndroid Build Coastguard Worker
1629*b9df5ad1SAndroid Build Coastguard Worker  # Do not mangle HTML when doing the replace by using BeatifulSoup
1630*b9df5ad1SAndroid Build Coastguard Worker  # - Use the 'html.parser' to avoid inserting <html><body> when decoding
1631*b9df5ad1SAndroid Build Coastguard Worker  soup = bs4.BeautifulSoup(text, features='html.parser')
1632*b9df5ad1SAndroid Build Coastguard Worker  wbr_tag = lambda: soup.new_tag('wbr') # must generate new tag every time
1633*b9df5ad1SAndroid Build Coastguard Worker
1634*b9df5ad1SAndroid Build Coastguard Worker  for navigable_string in soup.findAll(text=True):
1635*b9df5ad1SAndroid Build Coastguard Worker      parent = navigable_string.parent
1636*b9df5ad1SAndroid Build Coastguard Worker
1637*b9df5ad1SAndroid Build Coastguard Worker      # Insert each '$text<wbr>$foo' before the old '$text$foo'
1638*b9df5ad1SAndroid Build Coastguard Worker      split_by_wbr_list = wbr_filter(navigable_string).split("<wbr>")
1639*b9df5ad1SAndroid Build Coastguard Worker      for (split_string, last) in enumerate_with_last(split_by_wbr_list):
1640*b9df5ad1SAndroid Build Coastguard Worker          navigable_string.insert_before(split_string)
1641*b9df5ad1SAndroid Build Coastguard Worker
1642*b9df5ad1SAndroid Build Coastguard Worker          if not last:
1643*b9df5ad1SAndroid Build Coastguard Worker            # Note that 'insert' will move existing tags to this spot
1644*b9df5ad1SAndroid Build Coastguard Worker            # so make a new tag instead
1645*b9df5ad1SAndroid Build Coastguard Worker            navigable_string.insert_before(wbr_tag())
1646*b9df5ad1SAndroid Build Coastguard Worker
1647*b9df5ad1SAndroid Build Coastguard Worker      # Remove the old unmodified text
1648*b9df5ad1SAndroid Build Coastguard Worker      navigable_string.extract()
1649*b9df5ad1SAndroid Build Coastguard Worker
1650*b9df5ad1SAndroid Build Coastguard Worker  return soup.decode()
1651*b9df5ad1SAndroid Build Coastguard Worker
1652*b9df5ad1SAndroid Build Coastguard Workerdef copyright_year():
1653*b9df5ad1SAndroid Build Coastguard Worker  return _copyright_year
1654*b9df5ad1SAndroid Build Coastguard Worker
1655*b9df5ad1SAndroid Build Coastguard Workerdef infer_copyright_year_from_source(src_file, default_copyright_year):
1656*b9df5ad1SAndroid Build Coastguard Worker  """
1657*b9df5ad1SAndroid Build Coastguard Worker  Opens src_file and tries to infer the copyright year from the file
1658*b9df5ad1SAndroid Build Coastguard Worker  if it exists. Returns default_copyright_year if src_file is None, doesn't
1659*b9df5ad1SAndroid Build Coastguard Worker  exist, or the copyright year cannot be parsed from the first 15 lines.
1660*b9df5ad1SAndroid Build Coastguard Worker
1661*b9df5ad1SAndroid Build Coastguard Worker  Assumption:
1662*b9df5ad1SAndroid Build Coastguard Worker    - Copyright text must be in the first 15 lines of the src_file.
1663*b9df5ad1SAndroid Build Coastguard Worker      This should almost always be true.
1664*b9df5ad1SAndroid Build Coastguard Worker  """
1665*b9df5ad1SAndroid Build Coastguard Worker  if src_file is None:
1666*b9df5ad1SAndroid Build Coastguard Worker    return default_copyright_year
1667*b9df5ad1SAndroid Build Coastguard Worker
1668*b9df5ad1SAndroid Build Coastguard Worker  if not path.isfile(src_file):
1669*b9df5ad1SAndroid Build Coastguard Worker    return default_copyright_year
1670*b9df5ad1SAndroid Build Coastguard Worker
1671*b9df5ad1SAndroid Build Coastguard Worker  copyright_pattern = r"^.*Copyright \([Cc]\) (20\d\d) The Android Open Source Project$"
1672*b9df5ad1SAndroid Build Coastguard Worker  num_max_lines = 15
1673*b9df5ad1SAndroid Build Coastguard Worker
1674*b9df5ad1SAndroid Build Coastguard Worker  with open(src_file, "r") as f:
1675*b9df5ad1SAndroid Build Coastguard Worker    for i, line in enumerate(f):
1676*b9df5ad1SAndroid Build Coastguard Worker      if i >= num_max_lines:
1677*b9df5ad1SAndroid Build Coastguard Worker        break
1678*b9df5ad1SAndroid Build Coastguard Worker
1679*b9df5ad1SAndroid Build Coastguard Worker      years = re.findall(copyright_pattern, line.strip())
1680*b9df5ad1SAndroid Build Coastguard Worker      if len(years) > 0:
1681*b9df5ad1SAndroid Build Coastguard Worker        return years[0]
1682*b9df5ad1SAndroid Build Coastguard Worker
1683*b9df5ad1SAndroid Build Coastguard Worker  return default_copyright_year
1684*b9df5ad1SAndroid Build Coastguard Worker
1685*b9df5ad1SAndroid Build Coastguard Workerdef enum():
1686*b9df5ad1SAndroid Build Coastguard Worker  return _enum
1687*b9df5ad1SAndroid Build Coastguard Worker
1688*b9df5ad1SAndroid Build Coastguard Workerdef first_hal_minor_version(hal_major_version):
1689*b9df5ad1SAndroid Build Coastguard Worker  return 2 if hal_major_version == 3 else 0
1690*b9df5ad1SAndroid Build Coastguard Worker
1691*b9df5ad1SAndroid Build Coastguard Workerdef find_all_sections_added_in_hal(root, hal_major_version, hal_minor_version):
1692*b9df5ad1SAndroid Build Coastguard Worker  """
1693*b9df5ad1SAndroid Build Coastguard Worker  Find all descendants that are Section or InnerNamespace instances, which
1694*b9df5ad1SAndroid Build Coastguard Worker  were added in HIDL HAL version major.minor. The section is defined to be
1695*b9df5ad1SAndroid Build Coastguard Worker  added in a HAL version iff the lowest HAL version number of its entries is
1696*b9df5ad1SAndroid Build Coastguard Worker  that HAL version.
1697*b9df5ad1SAndroid Build Coastguard Worker
1698*b9df5ad1SAndroid Build Coastguard Worker  Args:
1699*b9df5ad1SAndroid Build Coastguard Worker    root: a Metadata instance
1700*b9df5ad1SAndroid Build Coastguard Worker    hal_major/minor_version: HAL version numbers
1701*b9df5ad1SAndroid Build Coastguard Worker
1702*b9df5ad1SAndroid Build Coastguard Worker  Returns:
1703*b9df5ad1SAndroid Build Coastguard Worker    A list of Section/InnerNamespace instances
1704*b9df5ad1SAndroid Build Coastguard Worker
1705*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
1706*b9df5ad1SAndroid Build Coastguard Worker    These are known as "sections" in the generated C code.
1707*b9df5ad1SAndroid Build Coastguard Worker  """
1708*b9df5ad1SAndroid Build Coastguard Worker  all_sections = find_all_sections(root)
1709*b9df5ad1SAndroid Build Coastguard Worker  new_sections = []
1710*b9df5ad1SAndroid Build Coastguard Worker  for section in all_sections:
1711*b9df5ad1SAndroid Build Coastguard Worker    min_major_version = None
1712*b9df5ad1SAndroid Build Coastguard Worker    min_minor_version = None
1713*b9df5ad1SAndroid Build Coastguard Worker    for entry in remove_hal_non_visible(find_unique_entries(section)):
1714*b9df5ad1SAndroid Build Coastguard Worker      min_major_version = (min_major_version or entry.hal_major_version)
1715*b9df5ad1SAndroid Build Coastguard Worker      min_minor_version = (min_minor_version or entry.hal_minor_version)
1716*b9df5ad1SAndroid Build Coastguard Worker      if entry.hal_major_version < min_major_version or \
1717*b9df5ad1SAndroid Build Coastguard Worker          (entry.hal_major_version == min_major_version and entry.hal_minor_version < min_minor_version):
1718*b9df5ad1SAndroid Build Coastguard Worker        min_minor_version = entry.hal_minor_version
1719*b9df5ad1SAndroid Build Coastguard Worker        min_major_version = entry.hal_major_version
1720*b9df5ad1SAndroid Build Coastguard Worker    if min_major_version == hal_major_version and min_minor_version == hal_minor_version:
1721*b9df5ad1SAndroid Build Coastguard Worker      new_sections.append(section)
1722*b9df5ad1SAndroid Build Coastguard Worker  return new_sections
1723*b9df5ad1SAndroid Build Coastguard Worker
1724*b9df5ad1SAndroid Build Coastguard Workerdef find_first_older_used_hal_version(section, hal_major_version, hal_minor_version):
1725*b9df5ad1SAndroid Build Coastguard Worker  hal_version = (0, 0)
1726*b9df5ad1SAndroid Build Coastguard Worker  for v in section.hal_versions:
1727*b9df5ad1SAndroid Build Coastguard Worker    if (v[0] > hal_version[0] or (v[0] == hal_version[0] and v[1] > hal_version[1])) and \
1728*b9df5ad1SAndroid Build Coastguard Worker        (v[0] < hal_major_version or (v[0] == hal_major_version and v[1] < hal_minor_version)):
1729*b9df5ad1SAndroid Build Coastguard Worker      hal_version = v
1730*b9df5ad1SAndroid Build Coastguard Worker  return hal_version
1731*b9df5ad1SAndroid Build Coastguard Worker
1732*b9df5ad1SAndroid Build Coastguard Worker# Some exceptions need to be made regarding enum value identifiers in AIDL.
1733*b9df5ad1SAndroid Build Coastguard Worker# Process them here.
1734*b9df5ad1SAndroid Build Coastguard Workerdef aidl_enum_value_name(name):
1735*b9df5ad1SAndroid Build Coastguard Worker  if name == 'ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5':
1736*b9df5ad1SAndroid Build Coastguard Worker    name = 'ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL_DEVICE'
1737*b9df5ad1SAndroid Build Coastguard Worker  return name
1738*b9df5ad1SAndroid Build Coastguard Worker
1739*b9df5ad1SAndroid Build Coastguard Workerdef aidl_enum_values(entry):
1740*b9df5ad1SAndroid Build Coastguard Worker  ignoreList = [
1741*b9df5ad1SAndroid Build Coastguard Worker    'ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END',
1742*b9df5ad1SAndroid Build Coastguard Worker    'ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8'
1743*b9df5ad1SAndroid Build Coastguard Worker  ]
1744*b9df5ad1SAndroid Build Coastguard Worker  return [
1745*b9df5ad1SAndroid Build Coastguard Worker    val for val in entry.enum.values if '%s_%s'%(csym(entry.name), val.name) not in ignoreList
1746*b9df5ad1SAndroid Build Coastguard Worker  ]
1747*b9df5ad1SAndroid Build Coastguard Worker
1748*b9df5ad1SAndroid Build Coastguard Workerdef java_symbol_for_aconfig_flag(flag_name):
1749*b9df5ad1SAndroid Build Coastguard Worker  """
1750*b9df5ad1SAndroid Build Coastguard Worker  Returns the java symbol for a give aconfig flag. This means converting
1751*b9df5ad1SAndroid Build Coastguard Worker  snake_case to lower camelCase. For example: The aconfig flag
1752*b9df5ad1SAndroid Build Coastguard Worker  'camera_ae_mode_low_light_boost' becomes 'cameraAeModeLowLightBoost'.
1753*b9df5ad1SAndroid Build Coastguard Worker
1754*b9df5ad1SAndroid Build Coastguard Worker  Args:
1755*b9df5ad1SAndroid Build Coastguard Worker    flag_name: str. aconfig flag in snake_case
1756*b9df5ad1SAndroid Build Coastguard Worker
1757*b9df5ad1SAndroid Build Coastguard Worker  Return:
1758*b9df5ad1SAndroid Build Coastguard Worker    Java symbol for the a config flag.
1759*b9df5ad1SAndroid Build Coastguard Worker  """
1760*b9df5ad1SAndroid Build Coastguard Worker  camel_case = "".join([t.capitalize() for t in flag_name.split("_")])
1761*b9df5ad1SAndroid Build Coastguard Worker  # first character should be lowercase
1762*b9df5ad1SAndroid Build Coastguard Worker  return camel_case[0].lower() + camel_case[1:]
1763