camera_metadata: add typedefs for java generated code

Change-Id: I619261b9645cda669a3b5ee7c79f4c56d4d4c3d4
diff --git a/camera/docs/CameraMetadataKeys.mako b/camera/docs/CameraMetadataKeys.mako
index 1c8d47c..2879d83 100644
--- a/camera/docs/CameraMetadataKeys.mako
+++ b/camera/docs/CameraMetadataKeys.mako
@@ -47,7 +47,7 @@
              * @hide
              */
             %endif
-            public static final class ${entry.get_name_minimal() | pascal_case}Key extends Key<${jtype(entry)}> {
+            public static final class ${entry.get_name_minimal() | pascal_case}Key extends Key<${jtype_boxed(entry)}> {
                 public enum Enum {
                   % for value,last in enumerate_with_last(entry.enum.values):
                     ${value.name | jidentifier}${"," if not last else ";"}
@@ -60,7 +60,7 @@
 
                 // TODO: remove requirement for constructor by making Key an interface
                 private ${entry.get_name_minimal() | pascal_case}Key(String name) {
-                    super(name, ${jtype(entry)}.class);
+                    super(name, ${jtype_boxed(entry)}.class);
                 }
 
               % if entry.enum.has_values_with_id:
@@ -93,14 +93,14 @@
 ## If we need to support more, we should use a recursive function here instead.. but the indentation gets trickier.
         public static final class ${inner_namespace.name| pascal_case} {
           % for entry in filter_visibility(inner_namespace.merged_entries, ('hidden','public')):
-            % if entry.enum:
+            % if entry.enum and not (entry.typedef and not entry.typedef.languages.get('java')):
 ${generate_enum(entry)}
             % if entry.applied_visibility == 'hidden':
             /**
              * @hide
              */
             %endif
-            public static final Key<${jtype(entry)}> ${entry.get_name_minimal() | csym} =
+            public static final Key<${jtype_boxed(entry)}> ${entry.get_name_minimal() | csym} =
                     new ${entry.get_name_minimal() | pascal_case}Key("${entry.name}");
             % else:
             % if entry.applied_visibility == 'hidden':
@@ -108,8 +108,8 @@
              * @hide
              */
             %endif
-            public static final Key<${jtype(entry)}> ${entry.get_name_minimal() | csym} =
-                    new Key<${jtype(entry)}>("${entry.name}", ${jclass(entry)});
+            public static final Key<${jtype_boxed(entry)}> ${entry.get_name_minimal() | csym} =
+                    new Key<${jtype_boxed(entry)}>("${entry.name}", ${jclass(entry)});
             % endif
           % endfor
         }
@@ -117,14 +117,14 @@
       % for entry in filter_visibility( \
           get_children_by_filtering_kind(section, xml_name, 'merged_entries'), \
                                          ('hidden', 'public')):
-        % if entry.enum:
+        % if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')):
 ${generate_enum(entry)}
           % if entry.applied_visibility == 'hidden':
         /**
          * @hide
          */
           %endif
-        public static final Key<${jtype(entry)}> ${entry.get_name_minimal() | csym} =
+        public static final Key<${jtype_boxed(entry)}> ${entry.get_name_minimal() | csym} =
                 new ${entry.get_name_minimal() | pascal_case}Key("${entry.name}");
         % else:
           % if entry.applied_visibility == 'hidden':
@@ -132,8 +132,8 @@
          * @hide
          */
           %endif
-        public static final Key<${jtype(entry)}> ${entry.get_name_minimal() | csym} =
-                new Key<${jtype(entry)}>("${entry.name}", ${jclass(entry)});
+        public static final Key<${jtype_boxed(entry)}> ${entry.get_name_minimal() | csym} =
+                new Key<${jtype_boxed(entry)}>("${entry.name}", ${jclass(entry)});
         % endif
       % endfor
 
diff --git a/camera/docs/docs.html b/camera/docs/docs.html
index 50f98e5..49d2e3c 100644
--- a/camera/docs/docs.html
+++ b/camera/docs/docs.html
@@ -1066,7 +1066,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -1552,7 +1552,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -2034,7 +2034,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -4481,7 +4481,7 @@
             <td class="entry_type">
                 <span class="entry_type_name">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as string]</span>
 
 
             </td> <!-- entry_type -->
@@ -4657,7 +4657,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -4723,7 +4723,7 @@
                 <span class="entry_type_array">
                   2 x n
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
                 <div class="entry_type_notes">list of resolution pairs</div>
 
 
@@ -4860,7 +4860,7 @@
             <td class="entry_type">
                 <span class="entry_type_name">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as string]</span>
 
 
             </td> <!-- entry_type -->
@@ -5076,7 +5076,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -5575,7 +5575,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as size]</span>
                 <div class="entry_type_notes">width and height of geometric correction map</div>
 
 
@@ -5688,7 +5688,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
                 <div class="entry_type_notes">width and height of lens shading map provided by the HAL.<wbr> (N,<wbr> M)</div>
 
 
@@ -7108,7 +7108,7 @@
                 <span class="entry_type_array">
                   4
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as rectangle]</span>
 
 
             </td> <!-- entry_type -->
@@ -7321,7 +7321,7 @@
                 <span class="entry_type_array">
                   n x 2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -7439,7 +7439,7 @@
                 <span class="entry_type_array">
                   n x 2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -7523,7 +7523,7 @@
                 <span class="entry_type_array">
                   n x 2
                 </span>
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -7587,7 +7587,7 @@
                 <span class="entry_type_array">
                   4
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as rectangle]</span>
 
 
             </td> <!-- entry_type -->
@@ -7836,7 +7836,7 @@
                 <span class="entry_type_array">
                   4
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as rectangle]</span>
                 <div class="entry_type_notes">Four ints defining the active pixel rectangle</div>
 
 
@@ -8051,7 +8051,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as size]</span>
                 <div class="entry_type_notes">width x height in millimeters</div>
 
 
@@ -8091,7 +8091,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as size]</span>
 
 
             </td> <!-- entry_type -->
@@ -9198,7 +9198,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -9239,7 +9239,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -9528,7 +9528,7 @@
                 <span class="entry_type_array">
                   2
                 </span>
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as size]</span>
                 <div class="entry_type_notes">width x height</div>
 
 
@@ -9726,7 +9726,7 @@
                 <span class="entry_type_array">
                   n x 4
                 </span>
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as rectangle]</span>
                 <div class="entry_type_notes">(xmin,<wbr> ymin,<wbr> xmax,<wbr> ymax).<wbr> (0,<wbr>0) is top-left of active pixel area</div>
 
 
@@ -9842,7 +9842,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -9923,7 +9923,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [system]</span>
+              <span class="entry_type_visibility"> [system as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -10603,7 +10603,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [hidden]</span>
+              <span class="entry_type_visibility"> [hidden as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -10680,7 +10680,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [hidden]</span>
+              <span class="entry_type_visibility"> [hidden as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -10911,7 +10911,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
@@ -10989,7 +10989,7 @@
             <td class="entry_type">
                 <span class="entry_type_name entry_type_name_enum">byte</span>
 
-              <span class="entry_type_visibility"> [public]</span>
+              <span class="entry_type_visibility"> [public as boolean]</span>
 
                 <ul class="entry_type_enum">
                   <li>
diff --git a/camera/docs/html.mako b/camera/docs/html.mako
index 0994bcd..937e19c 100644
--- a/camera/docs/html.mako
+++ b/camera/docs/html.mako
@@ -242,7 +242,7 @@
                 % endfor
                 </ul>
               % endif
-              <span class="entry_type_visibility"> [${prop.applied_visibility}]</span>
+              <span class="entry_type_visibility"> [${prop.applied_visibility}${" as %s" %prop.typedef.name if prop.typedef else ""}]</span>
               % if prop.type_notes is not None:
                 <div class="entry_type_notes">${prop.type_notes | wbr}</div>
               % endif
diff --git a/camera/docs/metadata-generate b/camera/docs/metadata-generate
index 9b3a009..ef19343 100755
--- a/camera/docs/metadata-generate
+++ b/camera/docs/metadata-generate
@@ -77,7 +77,8 @@
                           git rev-parse --show-toplevel 2> /dev/null)"
         if [[ $? -eq 0 ]]; then
             # Both staged and unstaged changes
-            local diff_result="$(git status --porcelain | egrep -c -v '^[?][?]')"
+            local diff_result="$(cd "$dir_path";
+                                 git status --porcelain | egrep -c -v '^[?][?]')"
             echo "Diff result was $diff_result" >& /dev/null
             echo "Diff result was $diff_result" >& /dev/null
             if [[ $diff_result -eq 0 ]]; then
diff --git a/camera/docs/metadata-validate b/camera/docs/metadata-validate
index d507d8e..a7755ad 100755
--- a/camera/docs/metadata-validate
+++ b/camera/docs/metadata-validate
@@ -28,6 +28,6 @@
 schema=$thisdir/metadata_properties.xsd
 doc=$1
 
-xmllint --noout --schema $schema $out $doc || exit 1
+xmllint --noout --schema $schema $doc || exit 1
 python $thisdir/metadata_validate.py $doc || exit 1
 
diff --git a/camera/docs/metadata_helpers.py b/camera/docs/metadata_helpers.py
index 97a9451..b8d1344 100644
--- a/camera/docs/metadata_helpers.py
+++ b/camera/docs/metadata_helpers.py
@@ -303,54 +303,122 @@
   """
   return 'TYPE_%s' %(what.upper())
 
-def jtype(entry):
+
+# Calculate a java type name from an entry with a Typedef node
+def _jtypedef_type(entry):
+  typedef = entry.typedef
+  additional = ''
+
+  # Hacky way to deal with arrays. Assume that if we have
+  # size 'Constant x N' the Constant is part of the Typedef size.
+  # So something sized just 'Constant', 'Constant1 x Constant2', etc
+  # is not treated as a real java array.
+  if entry.container == 'array':
+    has_variable_size = False
+    for size in entry.container_sizes:
+      try:
+        size_int = int(size)
+      except ValueError:
+        has_variable_size = True
+
+    if has_variable_size:
+      additional = '[]'
+
+  try:
+    name = typedef.languages['java']
+
+    return "%s%s" %(name, additional)
+  except KeyError:
+    return None
+
+# Box if primitive. Otherwise leave unboxed.
+def _jtype_box(type_name):
+  mapping = {
+    'boolean': 'Boolean',
+    'byte': 'Byte',
+    'int': 'Integer',
+    'float': 'Float',
+    'double': 'Double',
+    'long': 'Long'
+  }
+
+  return mapping.get(type_name, type_name)
+
+def jtype_unboxed(entry):
+  """
+  Calculate the Java type from an entry type string, to be used whenever we
+  need the regular type in Java. It's not boxed, so it can't be used as a
+  generic type argument when the entry type happens to resolve to a primitive.
+
+  Remarks:
+    Since Java generics cannot be instantiated with primitives, this version
+    is not applicable in that case. Use jtype_boxed instead for that.
+
+  Returns:
+    The string representing the Java type.
+  """
+  if not isinstance(entry, metadata_model.Entry):
+    raise ValueError("Expected entry to be an instance of Entry")
+
+  metadata_type = entry.type
+
+  java_type = None
+
+  if entry.typedef:
+    typedef_name = _jtypedef_type(entry)
+    if typedef_name:
+      java_type = typedef_name # already takes into account arrays
+
+  if not java_type:
+    if not java_type and entry.enum:
+      name = entry.name
+
+      name_without_ons = entry.get_name_as_list()[1:]
+      base_type = ".".join([pascal_case(i) for i in name_without_ons]) + \
+                   "Key.Enum"
+
+    else:
+      mapping = {
+        'int32': 'int',
+        'int64': 'long',
+        'float': 'float',
+        'double': 'double',
+        'byte': 'byte',
+        'rational': 'Rational'
+      }
+
+      base_type = mapping[metadata_type]
+
+    # Convert to array (enums, basic types)
+    if entry.container == 'array':
+      additional = '[]'
+    else:
+      additional = ''
+
+    java_type = '%s%s' %(base_type, additional)
+
+  # Now box this sucker.
+  return java_type
+
+def jtype_boxed(entry):
   """
   Calculate the Java type from an entry type string, to be used as a generic
   type argument in Java. The type is guaranteed to inherit from Object.
 
+  It will only box when absolutely necessary, i.e. int -> Integer[], but
+  int[] -> int[].
+
   Remarks:
     Since Java generics cannot be instantiated with primitives, this version
     will use boxed types when absolutely required.
 
   Returns:
-    The string representing the Java type.
+    The string representing the boxed Java type.
   """
+  unboxed_type = jtype_unboxed(entry)
+  return _jtype_box(unboxed_type)
 
-  if not isinstance(entry, metadata_model.Entry):
-    raise ValueError("Expected entry to be an instance of Entry")
-
-  primitive_type = entry.type
-
-  if entry.enum:
-    name = entry.name
-
-    name_without_ons = entry.get_name_as_list()[1:]
-    base_type = ".".join([pascal_case(i) for i in name_without_ons]) + \
-                 "Key.Enum"
-  else:
-    mapping = {
-      'int32': 'Integer',
-      'int64': 'Long',
-      'float': 'Float',
-      'double': 'Double',
-      'byte': 'Byte',
-      'rational': 'Rational'
-    }
-
-    base_type = mapping[primitive_type]
-
-  if entry.container == 'array':
-    additional = '[]'
-
-    #unbox if it makes sense
-    if primitive_type != 'rational' and not entry.enum:
-      base_type = jtype_primitive(primitive_type)
-  else:
-    additional = ''
-
-  return "%s%s" %(base_type, additional)
-
-def jtype_primitive(what):
+def _jtype_primitive(what):
   """
   Calculate the Java type from an entry type string.
 
@@ -392,16 +460,8 @@
   Returns:
     The ClassName.class string
   """
-  the_type = entry.type
-  try:
-    class_name = jtype_primitive(the_type)
-  except ValueError as e:
-    class_name = the_type
 
-  if entry.container == 'array':
-    class_name += "[]"
-
-  return "%s.class" %class_name
+  return "%s.class" %jtype_unboxed(entry)
 
 def jidentifier(what):
   """
diff --git a/camera/docs/metadata_model.py b/camera/docs/metadata_model.py
index 6b70288..66fe9d6 100644
--- a/camera/docs/metadata_model.py
+++ b/camera/docs/metadata_model.py
@@ -32,6 +32,7 @@
   EnumValue: A class corresponding to a <value> element within an Enum
   Metadata: Root node that also provides tree construction functionality.
   Tag: A node corresponding to a top level <tag> element.
+  Typedef: A node corresponding to a <typedef> element under <types>.
 """
 
 import sys
@@ -195,6 +196,7 @@
     parent: An edge to the parent Node. This is always None for Metadata.
     outer_namespaces: A sequence of immediate OuterNamespace children.
     tags: A sequence of all Tag instances available in the graph.
+    types: An iterable of all Typedef instances available in the graph.
   """
 
   def __init__(self):
@@ -214,6 +216,7 @@
     self._parent = None
     self._outer_namespaces = None
     self._tags = []
+    self._types = []
 
   @property
   def outer_namespaces(self):
@@ -226,6 +229,10 @@
   def tags(self):
     return (i for i in self._tags)
 
+  @property
+  def types(self):
+    return (i for i in self._types)
+
   def _get_properties(self):
 
     for i in self._entries:
@@ -253,6 +260,33 @@
     if not tag_ids:
       self._tags.append(Tag(tag, self, description))
 
+  def insert_type(self, type_name, type_selector="typedef", **kwargs):
+    """
+    Insert a type into the metadata.
+
+    Args:
+      type_name: A type's name
+      type_selector: The selector for the type, e.g. 'typedef'
+
+    Args (if type_selector == 'typedef'):
+      languages: A map of 'language name' -> 'fully qualified class path'
+
+    Example:
+      metadata.insert_type('rectangle', 'typedef',
+                           { 'java': 'android.graphics.Rect' })
+
+    Remarks:
+      Subsequent calls to insert_type with the same type name are safe (they
+      will be ignored)
+    """
+
+    if type_selector != 'typedef':
+      raise ValueError("Unsupported type_selector given " + type_selector)
+
+    type_names = [tp.name for tp in self.types if tp.name == tp]
+    if not type_names:
+      self._types.append(Typedef(type_name, self, kwargs.get('languages')))
+
   def insert_entry(self, entry):
     """
     Insert an entry into the metadata.
@@ -332,6 +366,8 @@
     self.validate_tree()
     self._construct_tags()
     self.validate_tree()
+    self._construct_types()
+    self.validate_tree()
     self._construct_clones()
     self.validate_tree()
     self._construct_outer_namespaces()
@@ -350,6 +386,16 @@
         if p not in tag.entries:
           tag._entries.append(p)
 
+  def _construct_types(self):
+    type_dict = self._dictionary_by_name(self.types)
+    for p in self._get_properties():
+      if p._type_name:
+        type_node = type_dict.get(p._type_name)
+        p._typedef = type_node
+
+        if p not in type_node.entries:
+          type_node._entries.append(p)
+
   def _construct_clones(self):
     for p in self._clones:
       target_kind = p.target_kind
@@ -567,6 +613,36 @@
   def _get_children(self):
     return None
 
+class Typedef(Node):
+  """
+  A typedef Node corresponding to a <typedef> element under a top-level <types>.
+
+  Attributes (Read-Only):
+    name: The name of this typedef as a string.
+    languages: A dictionary of 'language name' -> 'fully qualified class'.
+    parent: An edge to the parent, which is always the Metadata root node.
+    entries: An iterable over all entries which reference this typedef.
+  """
+  def __init__(self, name, parent, languages=None):
+    self._name        = name
+    self._parent      = parent
+
+    # all entries that have this typedef
+    self._entries     = []  # filled in by Metadata#construct_types
+
+    self._languages   = languages or {}
+
+  @property
+  def languages(self):
+    return self._languages
+
+  @property
+  def entries(self):
+    return (i for i in self._entries)
+
+  def _get_children(self):
+    return None
+
 class OuterNamespace(Node):
   """
   A node corresponding to a <namespace> element under <metadata>
@@ -949,6 +1025,7 @@
     units: A string units, or None.
     tags: A sequence of Tag nodes associated with this Entry.
     type_notes: A string describing notes for the type, or None.
+    typedef: A Typedef associated with this Entry, or None.
 
   Remarks:
     Subclass Clone can be used interchangeable with an Entry,
@@ -989,6 +1066,7 @@
       type_notes: A string with the notes for the type
       visibility: A string describing the visibility, eg 'system', 'hidden',
                   'public'
+      typedef: A string corresponding to a typedef's name attribute.
     """
 
     if kwargs.get('type') is None:
@@ -1070,6 +1148,10 @@
     return self._type_notes
 
   @property
+  def typedef(self):
+    return self._typedef
+
+  @property
   def enum(self):
     return self._enum
 
@@ -1091,7 +1173,7 @@
 
   def _init_common(self, **kwargs):
 
-    self._parent = None # filled in by MetadataSet::_construct_entries
+    self._parent = None # filled in by Metadata::_construct_entries
 
     self._container = kwargs.get('container')
     self._container_sizes = kwargs.get('container_sizes')
@@ -1109,9 +1191,11 @@
     self._notes = kwargs.get('notes')
 
     self._tag_ids = kwargs.get('tag_ids', [])
-    self._tags = None  # Filled in by MetadataSet::_construct_tags
+    self._tags = None  # Filled in by Metadata::_construct_tags
 
     self._type_notes = kwargs.get('type_notes')
+    self._type_name = kwargs.get('type_name')
+    self._typedef = None # Filled in by Metadata::_construct_types
 
     if kwargs.get('enum', False):
       self._enum = Enum(self, enum_values, enum_ids, enum_optionals, enum_notes)
@@ -1312,7 +1396,8 @@
                     'tuple_values',
                     'type',
                     'type_notes',
-                    'visibility'
+                    'visibility',
+                    'typedef'
                    ]
 
     for p in props_common:
diff --git a/camera/docs/metadata_parser_xml.py b/camera/docs/metadata_parser_xml.py
index 4e5c35f..f0ed12e 100755
--- a/camera/docs/metadata_parser_xml.py
+++ b/camera/docs/metadata_parser_xml.py
@@ -107,6 +107,15 @@
       for tag in tags.find_all('tag'):
         self.metadata.insert_tag(tag['id'], tag.string)
 
+    types = self.soup.types
+    if types is not None:
+      for tp in types.find_all('typedef'):
+        languages = {}
+        for lang in tp.find_all('language'):
+          languages[lang['name']] = lang.string
+
+        self.metadata.insert_type(tp['name'], 'typedef', languages=languages)
+
     # add all entries, preserving the ordering of the XML file
     # this is important for future ABI compatibility when generating code
     entry_filter = lambda x: x.name == 'entry' or x.name == 'clone'
@@ -149,6 +158,11 @@
     d['visibility'] = entry.get('visibility')
 
     #
+    # Typedef
+    #
+    d['type_name'] = entry.get('typedef')
+
+    #
     # Enum
     #
     if entry.get('enum', 'false') == 'true':
diff --git a/camera/docs/metadata_properties.xml b/camera/docs/metadata_properties.xml
index 77f7cc8..1e4fc17 100644
--- a/camera/docs/metadata_properties.xml
+++ b/camera/docs/metadata_properties.xml
@@ -40,6 +40,22 @@
         Tag only used by camera device HAL 2.x
     </tag>
   </tags>
+
+  <types>
+    <typedef name="rectangle">
+      <language name="java">android.graphics.Rect</language>
+    </typedef>
+    <typedef name="size">
+      <language name="java">android.hardware.photography.Size</language>
+    </typedef>
+    <typedef name="string">
+      <language name="java">String</language>
+    </typedef>
+    <typedef name="boolean">
+      <language name="java">boolean</language>
+    </typedef>
+  </types>
+
   <namespace name="android">
     <section name="colorCorrection">
       <controls>
@@ -130,7 +146,8 @@
           compensation of -1</notes>
           <tag id="BC" />
         </entry>
-        <entry name="aeLock" type="byte" visibility="public" enum="true">
+        <entry name="aeLock" type="byte" visibility="public" enum="true"
+               typedef="boolean">
           <enum>
             <value>OFF
             <notes>Autoexposure lock is disabled; the AE algorithm
@@ -366,7 +383,8 @@
           any active trigger, and return to initial AF state.</notes>
           <tag id="BC" />
         </entry>
-        <entry name="awbLock" type="byte" visibility="public" enum="true">
+        <entry name="awbLock" type="byte" visibility="public" enum="true"
+               typedef="boolean">
           <enum>
             <value>OFF
             <notes>Auto-whitebalance lock is disabled; the AWB
@@ -538,7 +556,7 @@
           <tag id="BC" />
         </entry>
         <entry name="videoStabilizationMode" type="byte" visibility="public"
-               enum="true">
+               enum="true" typedef="boolean">
           <enum>
             <value>OFF</value>
             <value>ON</value>
@@ -1026,7 +1044,8 @@
           <range>(-180 - 180], [-90,90], [-inf, inf]</range>
           <tag id="BC" />
         </entry>
-        <entry name="gpsProcessingMethod" type="byte" visibility="public">
+        <entry name="gpsProcessingMethod" type="byte" visibility="public"
+               typedef="string">
           <description>32 characters describing GPS algorithm to
           include in EXIF</description>
           <units>UTF-8 null-terminated string</units>
@@ -1059,7 +1078,7 @@
           <tag id="BC" />
         </entry>
         <entry name="thumbnailSize" type="int32" visibility="public"
-        container="array">
+        container="array" typedef="size">
           <array>
             <size>2</size>
           </array>
@@ -1071,7 +1090,7 @@
       </controls>
       <static>
         <entry name="availableThumbnailSizes" type="int32" visibility="public"
-        type_notes="list of resolution pairs" container="array">
+        type_notes="list of resolution pairs" container="array" typedef="size">
           <array>
             <size>2</size>
             <size>n</size>
@@ -1245,7 +1264,7 @@
           </entry>
           <entry name="geometricCorrectionMapSize" type="int32"
           type_notes="width and height of geometric correction map"
-          container="array">
+          container="array" typedef="size">
             <array>
               <size>2</size>
             </array>
@@ -1273,8 +1292,8 @@
             <tag id="V1" />
           </entry>
           <entry name="shadingMapSize" type="int32" visibility="public"
-          type_notes="width and height of lens shading map provided by the HAL. (N, M)"
-          container="array">
+                 type_notes="width and height of lens shading map provided by the HAL. (N, M)"
+                 container="array" typedef="size">
             <array>
               <size>2</size>
             </array>
@@ -1566,7 +1585,7 @@
     <section name="scaler">
       <controls>
         <entry name="cropRegion" type="int32" visibility="public"
-               container="array">
+               container="array" typedef="rectangle">
           <array>
             <size>4</size>
           </array>
@@ -1661,7 +1680,7 @@
           <tag id="BC" />
         </entry>
         <entry name="availableJpegSizes" type="int32" visibility="public"
-        container="array">
+        container="array" typedef="size">
           <array>
             <size>n</size>
             <size>2</size>
@@ -1696,7 +1715,7 @@
           <tag id="BC" />
         </entry>
         <entry name="availableProcessedSizes" type="int32" visibility="public"
-        container="array">
+        container="array" typedef="size">
           <array>
             <size>n</size>
             <size>2</size>
@@ -1725,7 +1744,7 @@
           <tag id="BC" />
         </entry>
         <entry name="availableRawSizes" type="int32"
-        container="array">
+        container="array" typedef="size">
           <array>
             <size>n</size>
             <size>2</size>
@@ -1776,7 +1795,8 @@
         <namespace name="info">
           <entry name="activeArraySize" type="int32" visibility="public"
           type_notes="Four ints defining the active pixel rectangle"
-          container="array">
+          container="array"
+          typedef="rectangle">
             <array>
               <size>4</size>
             </array>
@@ -1840,7 +1860,7 @@
           </entry>
           <entry name="physicalSize" type="float" visibility="public"
           type_notes="width x height in millimeters"
-          container="array">
+          container="array" typedef="size">
             <array>
               <size>2</size>
             </array>
@@ -1851,7 +1871,7 @@
             <tag id="BC" />
           </entry>
           <entry name="pixelArraySize" type="int32"
-          container="array">
+          container="array" typedef="size">
             <array>
               <size>2</size>
             </array>
@@ -2101,7 +2121,7 @@
           android.statistics.info.availableFaceDetectModes.</notes>
           <tag id="BC" />
         </entry>
-        <entry name="histogramMode" type="byte" enum="true">
+        <entry name="histogramMode" type="byte" enum="true" typedef="boolean">
           <enum>
             <value>OFF</value>
             <value>ON</value>
@@ -2110,7 +2130,7 @@
           generation</description>
           <tag id="V1" />
         </entry>
-        <entry name="sharpnessMapMode" type="byte" enum="true">
+        <entry name="sharpnessMapMode" type="byte" enum="true" typedef="boolean">
           <enum>
             <value>OFF</value>
             <value>ON</value>
@@ -2167,7 +2187,7 @@
             region.</description>
           </entry>
           <entry name="sharpnessMapSize" type="int32"
-          type_notes="width x height" container="array">
+          type_notes="width x height" container="array" typedef="size">
             <array>
               <size>2</size>
             </array>
@@ -2203,7 +2223,7 @@
         </entry>
         <entry name="faceRectangles" type="int32" visibility="public"
         type_notes="(xmin, ymin, xmax, ymax). (0,0) is top-left of active pixel area"
-        container="array">
+        container="array" typedef="rectangle">
           <array>
             <size>n</size>
             <size>4</size>
@@ -2407,7 +2427,8 @@
     </section>
     <section name="led">
       <controls>
-        <entry name="transmit" type="byte" visibility="hidden" enum="true">
+        <entry name="transmit" type="byte" visibility="hidden" enum="true"
+               typedef="boolean">
           <enum>
             <value>OFF</value>
             <value>ON</value>
@@ -2471,7 +2492,8 @@
     </section>
     <section name="blackLevel">
       <controls>
-        <entry name="lock" type="byte" visibility="public" enum="true">
+        <entry name="lock" type="byte" visibility="public" enum="true"
+               typedef="boolean">
           <enum>
             <value>OFF</value>
             <value>ON</value>
diff --git a/camera/docs/metadata_properties.xsd b/camera/docs/metadata_properties.xsd
index f567333..4e990bb 100644
--- a/camera/docs/metadata_properties.xsd
+++ b/camera/docs/metadata_properties.xsd
@@ -18,11 +18,23 @@
     targetNamespace="http://schemas.android.com/service/camera/metadata/"
     elementFormDefault="qualified">
 
-    <element name="metadata" type="tns:MetadataType"></element>
+    <element name="metadata" type="tns:MetadataType">
+        <key name="TypeNameKey">
+            <selector xpath="tns:types/tns:typedef" />
+            <field xpath="@name" />
+        </key>
+
+        <!-- ensure that <entry typedef="..."> refers to a valid <typedef name='..."/> -->
+        <keyref name="TypeNameKeyRef" refer="tns:TypeNameKey">
+            <selector xpath=".//tns:entry" /> <!-- recursively find any descendant entry -->
+            <field xpath="@typedef" />
+        </keyref>
+    </element>
 
     <complexType name="MetadataType">
         <sequence>
             <element name="tags" type="tns:TagsType" maxOccurs="1" minOccurs="0"></element>
+            <element name="types" type="tns:TypesType" maxOccurs="1" minOccurs="0"></element>
             <element name="namespace" type="tns:NamespaceType"
                 maxOccurs="unbounded" minOccurs="1">
             </element>
@@ -86,6 +98,36 @@
         </simpleContent>
     </complexType>
 
+    <complexType name="TypesType">
+        <sequence>
+            <element name="typedef" type="tns:TypedefType" maxOccurs="unbounded" minOccurs="0">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="TypedefType">
+        <sequence>
+            <element name="language" type="tns:LanguageType" maxOccurs="unbounded" minOccurs="1"></element>
+        </sequence>
+        <attribute name="name" type="string" use="required" />
+    </complexType>
+
+    <complexType name="LanguageType">
+        <simpleContent>
+            <extension base="string">
+                <attribute name="name" use="required">
+                    <simpleType>
+                        <restriction base="string">
+                            <enumeration value="java" />
+                            <enumeration value="c" />
+                            <enumeration value="c++" />
+                        </restriction>
+                    </simpleType>
+                </attribute>
+            </extension>
+        </simpleContent>
+    </complexType>
+
     <group name="BaseEntryGroup">
         <sequence>
             <element name="description" type="string" maxOccurs="1"
@@ -155,6 +197,7 @@
                 </restriction>
             </simpleType>
         </attribute>
+        <attribute name="typedef" type="string" />
     </complexType>
 
     <complexType name="EnumType">
diff --git a/camera/docs/metadata_template.mako b/camera/docs/metadata_template.mako
index 2fee0a1..5c03d3d 100644
--- a/camera/docs/metadata_template.mako
+++ b/camera/docs/metadata_template.mako
@@ -29,6 +29,16 @@
 % endfor
 </tags>
 
+<types>
+% for typedef in metadata.types:
+  <typedef name="${typedef.name}">
+    % for (language, klass) in typedef.languages.iteritems():
+      <language name="${language}">${klass}</language>
+    % endfor
+  </typedef>
+% endfor
+</types>
+
 % for root in metadata.outer_namespaces:
 <namespace name="${root.name}">
   % for section in root.sections:
@@ -84,6 +94,10 @@
           % if prop.container is not None:
                 container="${prop.container}"
           % endif
+
+          % if prop.typedef is not None:
+                typedef="${prop.typedef.name}"
+          % endif
             >
 
               % if prop.container == 'array':