am 1b601a44: Merge "MR1 is version 4.1, API 15." into ics-mr1

* commit '1b601a447247bcc373d417d7be4c89c1e6216b89':
  MR1 is version 4.1, API 15.
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index d9f3372..f48c35d 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -58,6 +58,7 @@
 LOCAL_INTERMEDIATE_SOURCE_DIR:=
 LOCAL_JAVACFLAGS:=
 LOCAL_JAVA_LIBRARIES:=
+LOCAL_JAVA_LAYERS_FILE:=
 LOCAL_NO_STANDARD_LIBRARIES:=
 LOCAL_CLASSPATH:=
 LOCAL_DROIDDOC_USE_STANDARD_DOCLET:=
diff --git a/core/definitions.mk b/core/definitions.mk
index 683ae16..867575a 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1455,6 +1455,8 @@
     $(PRIVATE_JAVACFLAGS) \
     \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \
     || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 )
+$(if $(PRIVATE_JAVA_LAYERS_FILE), $(hide) build/tools/java-layers.py \
+    $(PRIVATE_JAVA_LAYERS_FILE) \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq,)
 $(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list
 $(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
 $(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
diff --git a/core/java.mk b/core/java.mk
index 1cde62b..0c51da3 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -238,13 +238,19 @@
 	$(hide) $(ACP) -fp $(PRIVATE_SOURCE_FILE) $@
 ALL_MODULES.$(LOCAL_MODULE).STUBS := $(full_classes_stubs_jar)
 
+# The layers file allows you to enforce a layering between java packages.
+# Run build/tools/java-layers.py for more details.
+layers_file := $(addprefix $(LOCAL_PATH)/, $(LOCAL_JAVA_LAYERS_FILE))
+$(full_classes_compiled_jar): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
+
 # Compile the java files to a .jar file.
 # This intentionally depends on java_sources, not all_java_sources.
 # Deps for generated source files must be handled separately,
 # via deps on the target that generates the sources.
 $(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
-$(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file) \
-	$(RenderScript_file_stamp) $(proto_java_sources_file_stamp)
+$(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps)\
+                            $(jar_manifest_file) $(layers_file) \
+                            $(RenderScript_file_stamp) $(proto_java_sources_file_stamp)
 	$(transform-java-to-classes.jar)
 
 # All of the rules after full_classes_compiled_jar are very unlikely
diff --git a/core/main.mk b/core/main.mk
index 569d4dc..9b05f76 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -480,11 +480,16 @@
 	external/zlib
 else	# !BUILD_TINY_ANDROID
 
+ifneq ($(TARGET_SUBDIRS),)
+subdirs := $(TARGET_SUBDIRS)
+else
 #
 # Typical build; include any Android.mk files we can find.
 #
 subdirs := $(TOP)
 
+endif	# !TARGET_SUBDIRS
+
 FULL_BUILD := true
 
 endif	# !BUILD_TINY_ANDROID
diff --git a/target/product/generic_no_telephony.mk b/target/product/generic_no_telephony.mk
index 0d87fc3..a39f05a 100644
--- a/target/product/generic_no_telephony.mk
+++ b/target/product/generic_no_telephony.mk
@@ -60,6 +60,9 @@
     audio.primary.default \
     audio_policy.default
 
+PRODUCT_PACKAGES += \
+    local_time.default
+
 PRODUCT_COPY_FILES := \
         system/bluetooth/data/audio.conf:system/etc/bluetooth/audio.conf \
         system/bluetooth/data/auto_pairing.conf:system/etc/bluetooth/auto_pairing.conf \
diff --git a/tools/java-layers.py b/tools/java-layers.py
new file mode 100755
index 0000000..b3aec2b
--- /dev/null
+++ b/tools/java-layers.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+
+import os
+import re
+import sys
+
+def fail_with_usage():
+  sys.stderr.write("usage: java-layers.py DEPENDENCY_FILE SOURCE_DIRECTORIES...\n")
+  sys.stderr.write("\n")
+  sys.stderr.write("Enforces layering between java packages.  Scans\n")
+  sys.stderr.write("DIRECTORY and prints errors when the packages violate\n")
+  sys.stderr.write("the rules defined in the DEPENDENCY_FILE.\n")
+  sys.stderr.write("\n")
+  sys.stderr.write("Prints a warning when an unknown package is encountered\n")
+  sys.stderr.write("on the assumption that it should fit somewhere into the\n")
+  sys.stderr.write("layering.\n")
+  sys.stderr.write("\n")
+  sys.stderr.write("DEPENDENCY_FILE format\n")
+  sys.stderr.write("  - # starts comment\n")
+  sys.stderr.write("  - Lines consisting of two java package names:  The\n")
+  sys.stderr.write("    first package listed must not contain any references\n")
+  sys.stderr.write("    to any classes present in the second package, or any\n")
+  sys.stderr.write("    of its dependencies.\n")
+  sys.stderr.write("  - Lines consisting of one java package name:  The\n")
+  sys.stderr.write("    packge is assumed to be a high level package and\n")
+  sys.stderr.write("    nothing may depend on it.\n")
+  sys.stderr.write("  - Lines consisting of a dash (+) followed by one java\n")
+  sys.stderr.write("    package name: The package is considered a low level\n")
+  sys.stderr.write("    package and may not import any of the other packages\n")
+  sys.stderr.write("    listed in the dependency file.\n")
+  sys.stderr.write("  - Lines consisting of a plus (-) followed by one java\n")
+  sys.stderr.write("    package name: The package is considered \'legacy\'\n")
+  sys.stderr.write("    and excluded from errors.\n")
+  sys.stderr.write("\n")
+  sys.exit(1)
+
+class Dependency:
+  def __init__(self, filename, lineno, lower, top, lowlevel, legacy):
+    self.filename = filename
+    self.lineno = lineno
+    self.lower = lower
+    self.top = top
+    self.lowlevel = lowlevel
+    self.legacy = legacy
+    self.uppers = []
+    self.transitive = set()
+
+  def matches(self, imp):
+    for d in self.transitive:
+      if imp.startswith(d):
+        return True
+    return False
+
+class Dependencies:
+  def __init__(self, deps):
+    def recurse(obj, dep, visited):
+      global err
+      if dep in visited:
+        sys.stderr.write("%s:%d: Circular dependency found:\n"
+            % (dep.filename, dep.lineno))
+        for v in visited:
+          sys.stderr.write("%s:%d:    Dependency: %s\n"
+              % (v.filename, v.lineno, v.lower))
+        err = True
+        return
+      visited.append(dep)
+      for upper in dep.uppers:
+        obj.transitive.add(upper)
+        if upper in deps:
+          recurse(obj, deps[upper], visited)
+    self.deps = deps
+    self.parts = [(dep.lower.split('.'),dep) for dep in deps.itervalues()]
+    # transitive closure of dependencies
+    for dep in deps.itervalues():
+      recurse(dep, dep, [])
+    # disallow everything from the low level components
+    for dep in deps.itervalues():
+      if dep.lowlevel:
+        for d in deps.itervalues():
+          if dep != d and not d.legacy:
+            dep.transitive.add(d.lower)
+    # disallow the 'top' components everywhere but in their own package
+    for dep in deps.itervalues():
+      if dep.top and not dep.legacy:
+        for d in deps.itervalues():
+          if dep != d and not d.legacy:
+            d.transitive.add(dep.lower)
+    for dep in deps.itervalues():
+      dep.transitive = set([x+"." for x in dep.transitive])
+    if False:
+      for dep in deps.itervalues():
+        print "-->", dep.lower, "-->", dep.transitive
+
+  # Lookup the dep object for the given package.  If pkg is a subpackage
+  # of one with a rule, that one will be returned.  If no matches are found,
+  # None is returned.
+  def lookup(self, pkg):
+    # Returns the number of parts that match
+    def compare_parts(parts, pkg):
+      if len(parts) > len(pkg):
+        return 0
+      n = 0
+      for i in range(0, len(parts)):
+        if parts[i] != pkg[i]:
+          return 0
+        n = n + 1
+      return n
+    pkg = pkg.split(".")
+    matched = 0
+    result = None
+    for (parts,dep) in self.parts:
+      x = compare_parts(parts, pkg)
+      if x > matched:
+        matched = x
+        result = dep
+    return result
+
+def parse_dependency_file(filename):
+  global err
+  f = file(filename)
+  lines = f.readlines()
+  f.close()
+  def lineno(s, i):
+    i[0] = i[0] + 1
+    return (i[0],s)
+  n = [0]
+  lines = [lineno(x,n) for x in lines]
+  lines = [(n,s.split("#")[0].strip()) for (n,s) in lines]
+  lines = [(n,s) for (n,s) in lines if len(s) > 0]
+  lines = [(n,s.split()) for (n,s) in lines]
+  deps = {}
+  for n,words in lines:
+    if len(words) == 1:
+      lower = words[0]
+      top = True
+      legacy = False
+      lowlevel = False
+      if lower[0] == '+':
+        lower = lower[1:]
+        top = False
+        lowlevel = True
+      elif lower[0] == '-':
+        lower = lower[1:]
+        legacy = True
+      if lower in deps:
+        sys.stderr.write(("%s:%d: Package '%s' already defined on"
+            + " line %d.\n") % (filename, n, lower, deps[lower].lineno))
+        err = True
+      else:
+        deps[lower] = Dependency(filename, n, lower, top, lowlevel, legacy)
+    elif len(words) == 2:
+      lower = words[0]
+      upper = words[1]
+      if lower in deps:
+        dep = deps[lower]
+        if dep.top:
+          sys.stderr.write(("%s:%d: Can't add dependency to top level package "
+            + "'%s'\n") % (filename, n, lower))
+          err = True
+      else:
+        dep = Dependency(filename, n, lower, False, False, False)
+        deps[lower] = dep
+      dep.uppers.append(upper)
+    else:
+      sys.stderr.write("%s:%d: Too many words on line starting at \'%s\'\n" % (
+          filename, n, words[2]))
+      err = True
+  return Dependencies(deps)
+
+def find_java_files(srcs):
+  result = []
+  for d in srcs:
+    if d[0] == '@':
+      f = file(d[1:])
+      result.extend([fn for fn in [s.strip() for s in f.readlines()]
+          if len(fn) != 0])
+      f.close()
+    else:
+      for root, dirs, files in os.walk(d):
+        result.extend([os.sep.join((root,f)) for f in files
+            if f.lower().endswith(".java")])
+  return result
+
+COMMENTS = re.compile("//.*?\n|/\*.*?\*/", re.S)
+PACKAGE = re.compile("package\s+(.*)")
+IMPORT = re.compile("import\s+(.*)")
+
+def examine_java_file(deps, filename):
+  global err
+  # Yes, this is a crappy java parser.  Write a better one if you want to.
+  f = file(filename)
+  text = f.read()
+  f.close()
+  text = COMMENTS.sub("", text)
+  index = text.find("{")
+  if index < 0:
+    sys.stderr.write(("%s: Error: Unable to parse java. Can't find class "
+        + "declaration.\n") % filename)
+    err = True
+    return
+  text = text[0:index]
+  statements = [s.strip() for s in text.split(";")]
+  # First comes the package declaration.  Then iterate while we see import
+  # statements.  Anything else is either bad syntax that we don't care about
+  # because the compiler will fail, or the beginning of the class declaration.
+  m = PACKAGE.match(statements[0])
+  if not m:
+    sys.stderr.write(("%s: Error: Unable to parse java. Missing package "
+        + "statement.\n") % filename)
+    err = True
+    return
+  pkg = m.group(1)
+  imports = []
+  for statement in statements[1:]:
+    m = IMPORT.match(statement)
+    if not m:
+      break
+    imports.append(m.group(1))
+  # Do the checking
+  if False:
+    print filename
+    print "'%s' --> %s" % (pkg, imports)
+  dep = deps.lookup(pkg)
+  if not dep:
+    sys.stderr.write(("%s: Error: Package does not appear in dependency file: "
+      + "%s\n") % (filename, pkg))
+    err = True
+    return
+  for imp in imports:
+    if dep.matches(imp):
+      sys.stderr.write("%s: Illegal import in package '%s' of '%s'\n"
+          % (filename, pkg, imp))
+      err = True
+
+err = False
+
+def main(argv):
+  if len(argv) < 3:
+    fail_with_usage()
+  deps = parse_dependency_file(argv[1])
+
+  if err:
+    sys.exit(1)
+
+  java = find_java_files(argv[2:])
+  for filename in java:
+    examine_java_file(deps, filename)
+
+  if err:
+    sys.stderr.write("%s: Using this file as dependency file.\n" % argv[1])
+    sys.exit(1)
+
+  sys.exit(0)
+
+if __name__ == "__main__":
+  main(sys.argv)
+