Merge "Remove unused files from sun.nio.ch package"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index cb43851..ff0ae37 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -52,9 +52,10 @@
 core_resource_dirs := \
   luni/src/main/java \
   ojluni/src/main/resources/
-test_resource_dirs := $(call all-core-resource-dirs,test)
+test_resource_dirs := $(filter-out ojluni/%,$(call all-core-resource-dirs,test))
 test_src_files := $(call all-test-java-files-under,dalvik dalvik/test-rules dom harmony-tests json luni xml)
 ojtest_src_files := $(call all-test-java-files-under,ojluni)
+ojtest_resource_dirs := $(filter ojluni/%,$(call all-core-resource-dirs,test))
 
 ifeq ($(EMMA_INSTRUMENT),true)
 ifneq ($(EMMA_INSTRUMENT_STATIC),true)
@@ -215,7 +216,8 @@
 	nist-pkix-tests \
 	slf4j-jdk14 \
 	sqlite-jdbc \
-	tzdata-testing
+	tzdata-testing \
+        junit-params
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_ERROR_PRONE_FLAGS := -Xep:TryFailThrowable:ERROR
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -255,6 +257,7 @@
 # Make the core-ojtests library.
 ifeq ($(LIBCORE_SKIP_TESTS),)
     include $(CLEAR_VARS)
+    LOCAL_JAVA_RESOURCE_DIRS := $(ojtest_resource_dirs)
     LOCAL_NO_STANDARD_LIBRARIES := true
     LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp bouncycastle
     LOCAL_STATIC_JAVA_LIBRARIES := testng
@@ -272,10 +275,9 @@
 ifeq ($(LIBCORE_SKIP_TESTS),)
     include $(CLEAR_VARS)
     # Filter out SerializedLambdaTest because it depends on stub classes and won't actually run.
-    # Temporarily filter out java.time tests until they stabilize (b/28832222)
-    LOCAL_SRC_FILES := $(filter-out ojluni/src/test/java/time/% %/DeserializeMethodTest.java %/SerializedLambdaTest.java ojluni/src/test/java/util/stream/boot%,$(ojtest_src_files)) # Do not include anything from the boot* directories. Those directories need a custom bootclasspath to run.
+    LOCAL_SRC_FILES := $(filter-out %/DeserializeMethodTest.java %/SerializedLambdaTest.java ojluni/src/test/java/util/stream/boot%,$(ojtest_src_files)) # Do not include anything from the boot* directories. Those directories need a custom bootclasspath to run.
     # Include source code as part of JAR
-    LOCAL_JAVA_RESOURCE_DIRS := ojluni/src/test/dist
+    LOCAL_JAVA_RESOURCE_DIRS := ojluni/src/test/dist $(ojtest_resource_dirs)
     LOCAL_NO_STANDARD_LIBRARIES := true
     LOCAL_JAVA_LIBRARIES := \
         bouncycastle \
@@ -383,7 +385,8 @@
         nist-pkix-tests-host \
         slf4j-jdk14-hostdex \
         sqlite-jdbc-host \
-        tzdata-testing-hostdex
+        tzdata-testing-hostdex \
+        junit-params-hostdex
     LOCAL_JAVACFLAGS := $(local_javac_flags)
     LOCAL_MODULE_TAGS := optional
     LOCAL_JAVA_LANGUAGE_VERSION := 1.8
diff --git a/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
index 83777b0..b479d6f 100644
--- a/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
+++ b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
@@ -263,7 +263,7 @@
      * Returns the size (in bytes) occupied by a given primitive type on an
      * {@code EmulatedStackFrame}.
      */
-    private static int getSize(Class<?> type) {
+    public static int getSize(Class<?> type) {
         if (!type.isPrimitive()) {
             throw new IllegalArgumentException("type.isPrimitive() == false: " + type);
         }
@@ -377,6 +377,29 @@
                 referencesOffset = frame.references.length - 1;
             }
         }
+
+        public static void copyNext(StackFrameReader reader, StackFrameWriter writer,
+                                    Class<?> type) {
+            if (!type.isPrimitive()) {
+                writer.putNextReference(reader.nextReference(type), type);
+            } else if (type == boolean.class) {
+                writer.putNextBoolean(reader.nextBoolean());
+            } else if (type == byte.class) {
+                writer.putNextByte(reader.nextByte());
+            } else if (type == char.class) {
+                writer.putNextChar(reader.nextChar());
+            } else if (type == short.class) {
+                writer.putNextShort(reader.nextShort());
+            } else if (type == int.class) {
+                writer.putNextInt(reader.nextInt());
+            } else if (type == long.class) {
+                writer.putNextLong(reader.nextLong());
+            } else if (type == float.class) {
+                writer.putNextFloat(reader.nextFloat());
+            } else if (type == double.class) {
+                writer.putNextDouble(reader.nextDouble());
+            }
+        }
     }
 
     /**
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 76c16df..a5764f5 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1541,14 +1541,5 @@
   names: [
     "libcore.java.text.OldBidiTest#testUnicode9EmojisAreLtrNeutral"
   ]
-},
-{
-  description: "Test failures due to incomplete java.time implementation.",
-  bug: 28832222,
-  result: EXEC_FAILED,
-  names: [
-    "org.apache.harmony.tests.java.util.CalendarTest#test_getDisplayNameIILjava_util_Locale",
-    "org.apache.harmony.tests.java.util.CalendarTest#test_getDisplayNamesIILjava_util_Locale"
-  ]
 }
 ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index e5742d7..4e41c2a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -343,8 +343,9 @@
         } catch (IllegalArgumentException e) {
             // correct
         }
-        // tests nowhere
-        ia = Inet4Address.getByName("1.1.1.1");
+        // tests nowhere using an address from the  'IPv4 Address Blocks Reserved for Documentation'
+        // as specified in https://tools.ietf.org/html/rfc5737
+        ia = Inet4Address.getByName("192.0.2.1");
         assertFalse(ia.isReachable(1000));
         assertFalse(ia.isReachable(null, 0, 1000));
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
index 06a37c8..6284f0f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
@@ -968,7 +968,8 @@
 							.getAmPmStrings() : symbols.getEras();
 					assertDisplayNameMap(values, shortResult, 0);
 					assertDisplayNameMap(values, longResult, 0);
-					assertDisplayNameMap(values, allResult, 0);
+					assertTrue(allResult.size() >= shortResult.size());
+					assertTrue(allResult.size() >= longResult.size());
 					break;
 				case Calendar.MONTH:
 					values = symbols.getShortMonths();
@@ -977,8 +978,6 @@
 					assertDisplayNameMap(values, longResult, 0);
 					assertTrue(allResult.size() >= shortResult.size());
 					assertTrue(allResult.size() >= longResult.size());
-					assertTrue(allResult.size() <= shortResult.size()
-							+ longResult.size());
 					break;
 				case Calendar.DAY_OF_WEEK:
 					values = symbols.getShortWeekdays();
@@ -987,8 +986,6 @@
 					assertDisplayNameMap(values, longResult, 1);
 					assertTrue(allResult.size() >= shortResult.size());
 					assertTrue(allResult.size() >= longResult.size());
-					assertTrue(allResult.size() <= shortResult.size()
-							+ longResult.size());
 					break;
 				default:
 					assertNull(shortResult);
diff --git a/luni/src/test/java/libcore/java/lang/SystemTest.java b/luni/src/test/java/libcore/java/lang/SystemTest.java
index 2dc9d49..2de659d 100644
--- a/luni/src/test/java/libcore/java/lang/SystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/SystemTest.java
@@ -250,4 +250,14 @@
         } catch (SecurityException expected) {
         }
     }
+
+    // http://b/34867424
+    public void testIcuPathIncludesTimeZoneOverride() {
+        String icuDataPath = System.getProperty("android.icu.impl.ICUBinary.dataPath");
+        String[] paths = icuDataPath.split(":");
+        assertEquals(2, paths.length);
+
+        assertTrue(paths[0].contains("/misc/zoneinfo/current/icu"));
+        assertTrue(paths[1].contains("/usr/icu"));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
index 1e0c7b9..0f46460 100644
--- a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
@@ -119,16 +119,21 @@
      */
     public void testCountingProxy() throws Exception {
         CountingProxy countingProxy = CountingProxy.start();
+        Socket socket = new Socket();
         try {
-            Proxy proxy = countingProxy.asProxy();
-            assertEquals(Proxy.Type.HTTP, proxy.type());
-            SocketAddress address = proxy.address();
-            Socket socket = new Socket();
-            socket.connect(address, /* timeout (msec) */ 10); // attempt one connection
-            socket.close();
+            try {
+                Proxy proxy = countingProxy.asProxy();
+                assertEquals(Proxy.Type.HTTP, proxy.type());
+                SocketAddress address = proxy.address();
+                socket.connect(address, /* timeout (msec) */ 10); // attempt one connection
+            } finally {
+                int numConnections = countingProxy.shutdownAndGetConnectionCount();
+                assertEquals(1, numConnections);
+            }
         } finally {
-            int numConnections = countingProxy.shutdownAndGetConnectionCount();
-            assertEquals(1, numConnections);
+            // Closing this socket *after* shutdownAndGetConnectionCount() ensures
+            // that the server thread had a chance to count the connection attempt.
+            socket.close();
         }
     }
 
diff --git a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
index 8ecf72d..06286f0 100644
--- a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
@@ -24,8 +24,20 @@
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.HashSet;
+import java.util.Set;
 import libcore.io.IoUtils;
 
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 public class FileChannelTest extends junit.framework.TestCase {
     public void testReadOnlyByteArrays() throws Exception {
         ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
@@ -255,4 +267,55 @@
 
         return fc;
     }
+
+    /**
+     * The test verifies that FileChannel#open(Path, Set<OpenOption>, FileAttribute ...) returns the
+     * same object returned by #newFileChannel(Path, Set<OpenOption>, FileAttribute ...) method
+     * in given Paths's FileSystemProvider.
+     */
+    public void test_open_Path_Set_FileAttributes() throws IOException {
+        Path mockPath = mock(Path.class);
+        FileSystem mockFileSystem = mock(FileSystem.class);
+        FileSystemProvider mockFileSystemProvider = mock(FileSystemProvider.class);
+        FileChannel mockFileChannel = mock(FileChannel.class);
+
+        FileAttribute mockFileAttribute1 = mock(FileAttribute.class);
+        FileAttribute mockFileAttribute2 = mock(FileAttribute.class);
+
+        Set<StandardOpenOption> standardOpenOptions = new HashSet<>();
+        standardOpenOptions.add(READ);
+        standardOpenOptions.add(WRITE);
+
+        when(mockPath.getFileSystem()).thenReturn(mockFileSystem);
+        when(mockFileSystem.provider()).thenReturn(mockFileSystemProvider);
+        when(mockFileSystemProvider.newFileChannel(mockPath, standardOpenOptions,
+                mockFileAttribute1, mockFileAttribute2)).thenReturn(mockFileChannel);
+
+        assertEquals(mockFileChannel, FileChannel.open(mockPath, standardOpenOptions,
+                mockFileAttribute1, mockFileAttribute2));
+    }
+
+    /**
+     * The test verifies that FileChannel#open(Path, OpenOption ...) returns the
+     * same object returned by #newFileChannel(Path, OpenOption ...) method
+     * in given Paths's FileSystemProvider.
+     */
+    public void test_open_Path_OpenOptions() throws IOException {
+
+        Path mockPath = mock(Path.class);
+        FileSystem mockFileSystem = mock(FileSystem.class);
+        FileSystemProvider mockFileSystemProvider = mock(FileSystemProvider.class);
+        FileChannel mockFileChannel = mock(FileChannel.class);
+
+        Set<StandardOpenOption> standardOpenOptions = new HashSet<>();
+        standardOpenOptions.add(READ);
+        standardOpenOptions.add(WRITE);
+
+        when(mockPath.getFileSystem()).thenReturn(mockFileSystem);
+        when(mockFileSystem.provider()).thenReturn(mockFileSystemProvider);
+        when(mockFileSystemProvider.newFileChannel(mockPath, standardOpenOptions))
+                .thenReturn(mockFileChannel);
+
+        assertEquals(mockFileChannel, FileChannel.open(mockPath, READ, WRITE));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
index 04be662..564f7c9 100644
--- a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
@@ -19,8 +19,12 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.NonReadableChannelException;
 import java.nio.file.CopyOption;
 import java.nio.file.DirectoryNotEmptyException;
 import java.nio.file.DirectoryStream;
@@ -29,18 +33,34 @@
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.NotLinkException;
+import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.nio.file.attribute.BasicFileAttributeView;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
 import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
 import java.nio.file.spi.FileSystemProvider;
+import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
 import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static java.nio.file.StandardOpenOption.APPEND;
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.nio.file.StandardOpenOption.WRITE;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
 import static libcore.java.nio.file.FilesSetup.DATA_FILE;
@@ -53,6 +73,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
+@RunWith(JUnitParamsRunner.class)
 public class DefaultFileSystemProvider2Test {
 
     @Rule
@@ -362,4 +383,249 @@
             fail();
         } catch (NullPointerException expected) {}
     }
+
+    @Test
+    public void test_newFileChannel() throws IOException {
+        Set<OpenOption> openOptions = new HashSet<>();
+
+        // When file doesn't exist/
+        try {
+            // With CREATE & WRITE in OpenOptions.
+            openOptions.add(CREATE);
+            openOptions.add(WRITE);
+            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
+            assertTrue(Files.exists(filesSetup.getTestPath()));
+            Files.delete(filesSetup.getTestPath());
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        try {
+            // With CREATE & APPEND in OpenOption.
+            assertFalse(Files.exists(filesSetup.getTestPath()));
+            openOptions.add(CREATE);
+            openOptions.add(APPEND);
+            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
+            assertTrue(Files.exists(filesSetup.getTestPath()));
+            Files.delete(filesSetup.getTestPath());
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // When file exists.
+        try {
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        try {
+            // When file exists and READ in OpenOptions.
+            openOptions.add(READ);
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // Reading from a file opened with WRITE.
+        try {
+            openOptions.add(WRITE);
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc));
+            fail();
+        } catch (NonReadableChannelException expected) {
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // Writing to an exiting file.
+        try {
+            openOptions.add(WRITE);
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
+            fc.close();
+            assertEquals(overlayString1OnString2(TEST_FILE_DATA_2, TEST_FILE_DATA),
+                    readFromFile(filesSetup.getDataFilePath()));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // APPEND to an existing file.
+        try {
+            openOptions.add(WRITE);
+            openOptions.add(TRUNCATE_EXISTING);
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
+            fc.close();
+            assertEquals(TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath()));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // TRUNCATE an existing file.
+        try {
+            openOptions.add(WRITE);
+            openOptions.add(APPEND);
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions);
+            writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2);
+            fc.close();
+            assertEquals(TEST_FILE_DATA + TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath()));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+    }
+
+    @Test
+    @Parameters(method = "parameters_test_newFileChannel_NoSuchFileException")
+    public void test_newFileChannel_NoSuchFileException(Set<? extends OpenOption> openOptions)
+            throws IOException {
+        try {
+            provider.newFileChannel(filesSetup.getTestPath(), openOptions);
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @SuppressWarnings("unused")
+    private Object[] parameters_test_newFileChannel_NoSuchFileException() {
+        return new Object[] {
+                new Object[] { EnumSet.noneOf(StandardOpenOption.class) },
+                new Object[] { EnumSet.of(READ) },
+                new Object[] { EnumSet.of(WRITE) },
+                new Object[] { EnumSet.of(TRUNCATE_EXISTING) },
+                new Object[] { EnumSet.of(APPEND) },
+                new Object[] { EnumSet.of(CREATE, READ) },
+                new Object[] { EnumSet.of(CREATE, TRUNCATE_EXISTING) },
+                new Object[] { EnumSet.of(CREATE, READ) },
+        };
+    }
+
+    @Test
+    public void test_newFileChannel_withFileAttributes() throws IOException {
+        Set<OpenOption> openOptions = new HashSet<>();
+        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis());
+        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
+        FileAttribute<FileTime> unsupportedAttr = new MockFileAttribute<>(
+                "basic:lastModifiedTime", fileTime);
+
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
+        FileAttribute<Set<PosixFilePermission>> supportedAttr =
+                PosixFilePermissions.asFileAttribute(perm);
+
+        try {
+            // When file doesn't exists and with OpenOption CREATE & WRITE.
+            openOptions.clear();
+            openOptions.add(CREATE);
+            openOptions.add(WRITE);
+            provider.newFileChannel(filesSetup.getTestPath(), openOptions, unsupportedAttr);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        try {
+            // With OpenOption CREATE & WRITE.
+            openOptions.clear();
+            openOptions.add(CREATE);
+            openOptions.add(WRITE);
+            provider.newFileChannel(filesSetup.getTestPath(), openOptions, supportedAttr);
+            assertEquals(supportedAttr.value(), Files.getAttribute(filesSetup.getTestPath(),
+                    supportedAttr.name()));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // When file exists.
+        try {
+            provider.newFileChannel(filesSetup.getDataFilePath(), openOptions,
+                    unsupportedAttr);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+
+        // When file exists. No change in permissions.
+        try {
+            Set<PosixFilePermission> originalPermissions= (Set<PosixFilePermission>)
+                    Files.getAttribute(filesSetup.getDataFilePath(), supportedAttr.name());
+            FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions,
+                    supportedAttr);
+            assertEquals(originalPermissions, Files.getAttribute(filesSetup.getDataFilePath(),
+                    supportedAttr.name()));
+        } finally {
+            filesSetup.reset();
+            openOptions.clear();
+        }
+    }
+
+
+    @Test
+    public void test_newFileChannel_NPE() throws IOException {
+        try {
+            provider.newByteChannel(null, new HashSet<>(), new MockFileAttribute<>());
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            provider.newByteChannel(filesSetup.getTestPath(), null, new MockFileAttribute<>());
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            provider.newByteChannel(filesSetup.getTestPath(), new HashSet<>(), null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    String readFromFileChannel(FileChannel fc) throws IOException {
+        ByteBuffer bb = ByteBuffer.allocate(20);
+        fc.read(bb);
+        return new String(bb.array(), "UTF-8").trim();
+    }
+
+    void writeToFileChannel(FileChannel fc, String data) throws IOException {
+        fc.write(ByteBuffer.wrap(data.getBytes()));
+    }
+
+    String overlayString1OnString2(String s1, String s2) {
+        return s1 + s2.substring(s1.length());
+    }
+
+    static class MockFileAttribute<T> implements FileAttribute {
+
+        String name;
+        T value;
+
+        MockFileAttribute() {
+        }
+
+        MockFileAttribute(String name, T value) {
+            this.name = name;
+            this.value = value;
+        }
+
+        @Override
+        public String name() {
+            return name;
+        }
+
+        @Override
+        public T value() {
+            return value;
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/java/security/PKCS12AttributeTest.java b/luni/src/test/java/libcore/java/security/PKCS12AttributeTest.java
index 62894d6..f4b2802 100644
--- a/luni/src/test/java/libcore/java/security/PKCS12AttributeTest.java
+++ b/luni/src/test/java/libcore/java/security/PKCS12AttributeTest.java
@@ -14,11 +14,12 @@
  * limitations under the License
  */
 
-package java.security;
+package libcore.java.security;
 
 import junit.framework.TestCase;
 
 import java.io.IOException;
+import java.security.PKCS12Attribute;
 import java.util.Arrays;
 
 
diff --git a/luni/src/test/java/libcore/java/security/PrincipalTest.java b/luni/src/test/java/libcore/java/security/PrincipalTest.java
index de20325..43a8e68 100644
--- a/luni/src/test/java/libcore/java/security/PrincipalTest.java
+++ b/luni/src/test/java/libcore/java/security/PrincipalTest.java
@@ -14,10 +14,11 @@
  * limitations under the License
  */
 
-package java.security;
+package libcore.java.security;
 
 import junit.framework.TestCase;
 
+import java.security.Principal;
 import java.util.Collections;
 import java.util.HashSet;
 
@@ -71,4 +72,4 @@
             return this.name.equals(((PrincipalWithEqualityByName) other).getName());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 22ebae5..04f4465 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -981,7 +981,8 @@
         // is prioritized over the properties in ICUConfig.properties. The issue with using
         // that is that it doesn't play well with jarjar and it needs complicated build rules
         // to change its default value.
-        p.put("android.icu.impl.ICUBinary.dataPath", getenv("ANDROID_ROOT") + "/usr/icu");
+        String icuDataPath = generateIcuDataPath();
+        p.put("android.icu.impl.ICUBinary.dataPath", icuDataPath);
 
         parsePropertyAssignments(p, specialProperties());
 
@@ -1007,6 +1008,37 @@
         return p;
     }
 
+    private static String generateIcuDataPath() {
+        StringBuilder icuDataPathBuilder = new StringBuilder();
+        // ICU should first look in ANDROID_DATA. This is used for (optional) timezone data.
+        String dataIcuDataPath = getEnvironmentPath("ANDROID_DATA", "/misc/zoneinfo/current/icu");
+        if (dataIcuDataPath != null) {
+            icuDataPathBuilder.append(dataIcuDataPath);
+        }
+
+        // ICU should always look in ANDROID_ROOT.
+        String systemIcuDataPath = getEnvironmentPath("ANDROID_ROOT", "/usr/icu");
+        if (systemIcuDataPath != null) {
+            if (icuDataPathBuilder.length() > 0) {
+                icuDataPathBuilder.append(":");
+            }
+            icuDataPathBuilder.append(systemIcuDataPath);
+        }
+        return icuDataPathBuilder.toString();
+    }
+
+    /**
+     * Creates a path by combining the value of an environment variable with a relative path.
+     * Returns {@code null} if the environment variable is not set.
+     */
+    private static String getEnvironmentPath(String environmentVariable, String path) {
+        String variable = getenv(environmentVariable);
+        if (variable == null) {
+            return null;
+        }
+        return variable + path;
+    }
+
     private static Properties initProperties() {
         Properties p = new PropertiesWithNonOverrideableDefaults(unchangeableProps);
         setDefaultChangeableProperties(p);
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index cd5f70d..5b7ca6f 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -2186,23 +2186,23 @@
     MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
         int insCount = values.length;
         Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
-        if (insCount == 0)  return target;
+        if (insCount == 0)  {
+            return target;
+        }
 
-        // BoundMethodHandle result = target.rebind();
-        // for (int i = 0; i < insCount; i++) {
-        //     Object value = values[i];
-        //     Class<?> ptype = ptypes[pos+i];
-        //     if (ptype.isPrimitive()) {
-        //         result = insertArgumentPrimitive(result, pos, ptype, value);
-        //     } else {
-        //         value = ptype.cast(value);  // throw CCE if needed
-        //         result = result.bindArgumentL(pos, value);
-        //     }
-        // }
-        // return result;
+        // Throw ClassCastExceptions early if we can't cast any of the provided values
+        // to the required type.
+        for (int i = 0; i < insCount; i++) {
+            final Class<?> ptype = ptypes[pos + i];
+            if (!ptype.isPrimitive()) {
+                ptypes[pos + i].cast(values[i]);
+            } else {
+                // Will throw a ClassCastException if something terrible happens.
+                values[i] = Wrapper.forPrimitiveType(ptype).convert(values[i], ptype);
+            }
+        }
 
-        // TODO(narayan): Implement insertArguments, remove @hide.
-        throw new UnsupportedOperationException("MethodHandles.insertArguments is not implemented");
+        return new Transformers.InsertArguments(target, pos, values);
     }
 
     // Android-changed: insertArgumentPrimitive is unused.
@@ -2421,30 +2421,12 @@
     public static
     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
         filterArgumentsCheckArity(target, pos, filters);
-        MethodHandle adapter = target;
-        int curPos = pos-1;  // pre-incremented
-        for (MethodHandle filter : filters) {
-            curPos += 1;
-            if (filter == null)  continue;  // ignore null elements of filters
-            adapter = filterArgument(adapter, curPos, filter);
+
+        for (int i = 0; i < filters.length; ++i) {
+            filterArgumentChecks(target, i + pos, filters[i]);
         }
-        return adapter;
-    }
 
-    /*non-public*/ static
-    MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
-        filterArgumentChecks(target, pos, filter);
-        // MethodType targetType = target.type();
-        // MethodType filterType = filter.type();
-        // BoundMethodHandle result = target.rebind();
-        // Class<?> newParamType = filterType.parameterType(0);
-        // LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
-        // MethodType newType = targetType.changeParameterType(pos, newParamType);
-        // result = result.copyWithExtendL(newType, lform, filter);
-        // return result;
-
-        // TODO(narayan): Implement filterArguments, remove @hide.
-        throw new UnsupportedOperationException("MethodHandles.filterArgument is not implemented");
+        return new Transformers.FilterArguments(target, pos, filters);
     }
 
     private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
@@ -2573,21 +2555,7 @@
     public static
     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
         MethodType newType = collectArgumentsChecks(target, pos, filter);
-        MethodType collectorType = filter.type();
-
-        // BoundMethodHandle result = target.rebind();
-        // LambdaForm lform;
-        // if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
-        //     lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
-        //     if (lform != null) {
-        //         return result.copyWith(newType, lform);
-        //     }
-        // }
-        // lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
-        // return result.copyWithExtendL(newType, lform, filter);
-
-        // TODO(narayan): Implement collectArguments, remove @hide.
-        throw new UnsupportedOperationException("MethodHandles.collectArguments is not implemented");
+        return new Transformers.CollectArguments(target, filter, pos, newType);
     }
 
     private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
@@ -2764,8 +2732,7 @@
         MethodType combinerType = combiner.type();
         Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
 
-        // TODO(narayan): Implement foldArguments, remove @hide.
-        throw new UnsupportedOperationException("MethodHandles.foldArguments is not implemented");
+        return new Transformers.FoldArguments(target, combiner);
     }
 
     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
diff --git a/ojluni/src/main/java/java/lang/invoke/Transformers.java b/ojluni/src/main/java/java/lang/invoke/Transformers.java
index a52d9d1..10ce855 100644
--- a/ojluni/src/main/java/java/lang/invoke/Transformers.java
+++ b/ojluni/src/main/java/java/lang/invoke/Transformers.java
@@ -29,6 +29,7 @@
 import java.lang.reflect.Modifier;
 import sun.invoke.util.Wrapper;
 import sun.misc.Unsafe;
+import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
 
 /**
  * @hide Public for testing only.
@@ -1053,7 +1054,6 @@
         }
     }
 
-
     /**
      * Implements MethodHandle.asSpreader / MethodHandles.spreadInvoker.
      */
@@ -1469,4 +1469,340 @@
             targetFrame.copyReturnValueTo(callerFrame);
         }
     }
+
+    /*
+     * Implements MethodHandles.filterArguments.
+     */
+    static class FilterArguments extends Transformer {
+        /** The target handle. */
+        private final MethodHandle target;
+        /** Index of the first argument to filter */
+        private final int pos;
+        /** The list of filters to apply */
+        private final MethodHandle[] filters;
+
+        private final StackFrameWriter writer;
+        private final StackFrameReader reader;
+
+        private final StackFrameWriter filterWriter;
+        private final StackFrameReader filterReader;
+
+        FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) {
+            super(deriveType(target, pos, filters));
+
+            this.target = target;
+            this.pos = pos;
+            this.filters = filters;
+
+            this.writer = new StackFrameWriter();
+            this.reader = new StackFrameReader();
+
+            this.filterReader = new StackFrameReader();
+            this.filterWriter = new StackFrameWriter();
+        }
+
+        private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
+            final Class<?>[] filterArgs = new Class<?>[filters.length];
+            for (int i = 0; i < filters.length; ++i) {
+                filterArgs[i] = filters[i].type().parameterType(0);
+            }
+
+            return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            reader.attach(stackFrame);
+
+            EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
+            writer.attach(transformedFrame);
+
+            final Class<?>[] ptypes = target.type().ptypes();
+            for (int i = 0; i < ptypes.length; ++i) {
+                // Check whether the current argument has a filter associated with it.
+                // If it has no filter, no further action need be taken.
+                final Class<?> ptype = ptypes[i];
+                final MethodHandle filter;
+                if (i < pos) {
+                    filter = null;
+                } else if (i >= pos + filters.length) {
+                    filter = null;
+                } else {
+                    filter = filters[i - pos];
+                }
+
+                if (filter != null) {
+                    // Note that filter.type() must be (ptype)ptype - this is checked before
+                    // this transformer is created.
+                    EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+
+                    //  Copy the next argument from the stack frame to the filter frame.
+                    filterWriter.attach(filterFrame);
+                    copyNext(reader, filterWriter, filter.type().ptypes()[0]);
+
+                    filter.invoke(filterFrame);
+
+                    // Copy the argument back from the filter frame to the stack frame.
+                    filterReader.attach(filterFrame);
+                    filterReader.makeReturnValueAccessor();
+                    copyNext(filterReader, writer, ptype);
+                } else {
+                    // There's no filter associated with this frame, just copy the next argument
+                    // over.
+                    copyNext(reader, writer, ptype);
+                }
+            }
+
+            target.invoke(transformedFrame);
+            transformedFrame.copyReturnValueTo(stackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.collectArguments.
+     */
+    static class CollectArguments extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle collector;
+        private final int pos;
+
+        /** The range of input arguments we copy to the collector. */
+        private final Range collectorRange;
+
+        /**
+         * The first range of arguments we copy to the target. These are arguments
+         * in the range [0, pos). Note that arg[pos] is the return value of the filter.
+         */
+        private final Range range1;
+
+        /**
+         * The second range of arguments we copy to the target. These are arguments in the range
+         * (pos, N], where N is the number of target arguments.
+         */
+        private final Range range2;
+
+        private final StackFrameReader reader;
+        private final StackFrameWriter writer;
+
+        private final int referencesOffset;
+        private final int stackFrameOffset;
+
+        CollectArguments(MethodHandle target, MethodHandle collector, int pos,
+                         MethodType adapterType) {
+            super(adapterType);
+
+            this.target = target;
+            this.collector = collector;
+            this.pos = pos;
+
+            final int numFilterArgs = collector.type().parameterCount();
+            final int numAdapterArgs = type().parameterCount();
+            collectorRange = Range.of(type(), pos, pos + numFilterArgs);
+
+            range1 = Range.of(type(), 0, pos);
+            if (pos + numFilterArgs < numAdapterArgs) {
+                this.range2 = Range.of(type(), pos + numFilterArgs, numAdapterArgs);
+            } else {
+                this.range2 = null;
+            }
+
+            reader = new StackFrameReader();
+            writer = new StackFrameWriter();
+
+            // Calculate the number of primitive bytes (or references) we copy to the
+            // target frame based on the return value of the combiner.
+            final Class<?> collectorRType = collector.type().rtype();
+            if (collectorRType == void.class) {
+                stackFrameOffset = 0;
+                referencesOffset = 0;
+            } else if (collectorRType.isPrimitive()) {
+                stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
+                referencesOffset = 0;
+            } else {
+                stackFrameOffset = 0;
+                referencesOffset = 1;
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            // First invoke the collector.
+            EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
+            stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
+            collector.invoke(filterFrame);
+
+            // Start constructing the target frame.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+            stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
+
+            // If one of these offsets is not zero, we have a return value to copy.
+            if (referencesOffset != 0 || stackFrameOffset != 0) {
+                reader.attach(filterFrame).makeReturnValueAccessor();
+                writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
+                copyNext(reader, writer, target.type().ptypes()[0]);
+            }
+
+            if (range2 != null) {
+                stackFrame.copyRangeTo(targetFrame, range2,
+                        range1.numReferences + referencesOffset,
+                        range2.numBytes + stackFrameOffset);
+            }
+
+            target.invoke(targetFrame);
+            targetFrame.copyReturnValueTo(stackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.foldArguments.
+     */
+    static class FoldArguments extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle combiner;
+
+        private final Range combinerArgs;
+        private final Range targetArgs;
+
+        private final StackFrameReader reader;
+        private final StackFrameWriter writer;
+
+        private final int referencesOffset;
+        private final int stackFrameOffset;
+
+        FoldArguments(MethodHandle target, MethodHandle combiner) {
+            super(deriveType(target, combiner));
+
+            this.target = target;
+            this.combiner = combiner;
+
+            combinerArgs = Range.all(combiner.type());
+            targetArgs = Range.all(type());
+
+            reader = new StackFrameReader();
+            writer = new StackFrameWriter();
+
+            final Class<?> combinerRType = combiner.type().rtype();
+            if (combinerRType == void.class) {
+                stackFrameOffset = 0;
+                referencesOffset = 0;
+            } else if (combinerRType.isPrimitive()) {
+                stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
+                referencesOffset = 0;
+            } else {
+                stackFrameOffset = 0;
+                referencesOffset = 1;
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            // First construct the combiner frame and invoke it.
+            EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
+            stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
+            combiner.invoke(combinerFrame);
+
+            // Create the stack frame for the target.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            // If one of these offsets is not zero, we have a return value to copy.
+            if (referencesOffset != 0 || stackFrameOffset != 0) {
+                reader.attach(combinerFrame).makeReturnValueAccessor();
+                writer.attach(targetFrame);
+                copyNext(reader, writer, target.type().ptypes()[0]);
+            }
+
+            stackFrame.copyRangeTo(targetFrame, targetArgs, referencesOffset, stackFrameOffset);
+            target.invoke(targetFrame);
+
+            targetFrame.copyReturnValueTo(stackFrame);
+        }
+
+        private static MethodType deriveType(MethodHandle target, MethodHandle combiner) {
+            if (combiner.type().rtype() == void.class) {
+                return target.type();
+            }
+
+            return target.type().dropParameterTypes(0, 1);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.insertArguments.
+     */
+    static class InsertArguments extends Transformer {
+        private final MethodHandle target;
+        private final int pos;
+        private final Object[] values;
+
+        private final Range range1;
+        private final Range range2;
+        private final StackFrameWriter writer;
+
+        InsertArguments(MethodHandle target, int pos, Object[] values) {
+            super(target.type().dropParameterTypes(pos, pos + values.length));
+            this.target = target;
+            this.pos = pos;
+            this.values = values;
+
+            final MethodType type = type();
+            range1 = EmulatedStackFrame.Range.of(type, 0, pos);
+            range2 = Range.of(type, pos, type.parameterCount());
+
+            writer = new StackFrameWriter();
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+
+            // Copy all arguments before |pos|.
+            stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
+
+            // Attach a stack frame writer so that we can copy the next |values.length|
+            // arguments.
+            writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
+
+            // Copy all the arguments supplied in |values|.
+            int referencesCopied = 0;
+            int bytesCopied = 0;
+            final Class<?>[] ptypes = target.type().ptypes();
+            for (int i = 0; i < values.length; ++i) {
+                final Class<?> ptype = ptypes[i + pos];
+                if (ptype.isPrimitive()) {
+                    if (ptype == boolean.class) {
+                        writer.putNextBoolean((boolean) values[i]);
+                    } else if (ptype == byte.class) {
+                        writer.putNextByte((byte) values[i]);
+                    } else if (ptype == char.class) {
+                        writer.putNextChar((char) values[i]);
+                    } else if (ptype == short.class) {
+                        writer.putNextShort((short) values[i]);
+                    } else if (ptype == int.class) {
+                        writer.putNextInt((int) values[i]);
+                    } else if (ptype == long.class) {
+                        writer.putNextLong((long) values[i]);
+                    } else if (ptype == float.class) {
+                        writer.putNextFloat((float) values[i]);
+                    } else if (ptype == double.class) {
+                        writer.putNextDouble((double) values[i]);
+                    }
+
+                    bytesCopied += EmulatedStackFrame.getSize(ptype);
+                } else {
+                    writer.putNextReference(values[i], ptype);
+                    referencesCopied++;
+                }
+            }
+
+            // Copy all remaining arguments.
+            if (range2 != null) {
+                stackFrame.copyRangeTo(calleeFrame, range2,
+                        range1.numReferences + referencesCopied,
+                        range1.numBytes + bytesCopied);
+            }
+
+            target.invoke(calleeFrame);
+            calleeFrame.copyReturnValueTo(stackFrame);
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 2a10aee..60c1c97 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -2034,6 +2034,11 @@
      * @since 1.6
      */
     public String getDisplayName(int field, int style, Locale locale) {
+        // Android-changed: Android has traditionally treated ALL_STYLES as SHORT, even though
+        // it's not documented to be a valid value for style.
+        if (style == ALL_STYLES) {
+            style = SHORT;
+        }
         if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
                             ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
             return null;
@@ -2174,6 +2179,10 @@
             baseStyle < minStyle || baseStyle > maxStyle) {
             throw new IllegalArgumentException();
         }
+        // Android-changed: 3 is not a valid base style (1, 2 and 4 are, though), throw if used.
+        if (baseStyle == 3) {
+            throw new IllegalArgumentException();
+        }
         if (locale == null) {
             throw new NullPointerException();
         }
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index d6d8502..ca1b990 100644
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,13 @@
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
 
 import libcore.icu.LocaleData;
 import sun.misc.FpUtils;
@@ -124,7 +131,7 @@
  *   import static java.util.Calendar.*;
  *
  *   Calendar c = new GregorianCalendar(1995, MAY, 23);
- *   String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ *   String s = String.format("Duke's Birthday: %1$tb %1$te, %1$tY", c);
  *   // -&gt; s == "Duke's Birthday: May 23, 1995"
  * </pre></blockquote>
  *
@@ -183,7 +190,7 @@
  * <p> The optional <i>flags</i> is a set of characters that modify the output
  * format.  The set of valid flags depends on the conversion.
  *
- * <p> The optional <i>width</i> is a non-negative decimal integer indicating
+ * <p> The optional <i>width</i> is a positive decimal integer indicating
  * the minimum number of characters to be written to the output.
  *
  * <p> The optional <i>precision</i> is a non-negative decimal integer usually
@@ -246,7 +253,7 @@
  * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
  * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
  * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
- * BigInteger}
+ * BigInteger} (but not {@code char} or {@link Character})
  *
  * <li><b>Floating Point</b> - may be applied to Java floating-point types:
  * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
@@ -255,8 +262,8 @@
  * </ol>
  *
  * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
- * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, and
- * {@link Date}.
+ * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
+ * {@link Date} and {@link TemporalAccessor TemporalAccessor}
  *
  * <li> <b>Percent</b> - produces a literal {@code '%'}
  * (<tt>'&#92;u0025'</tt>)
@@ -337,7 +344,9 @@
  * <tr><td valign="top">{@code 'a'}, {@code 'A'}
  *     <td valign="top"> floating point
  *     <td> The result is formatted as a hexadecimal floating-point number with
- *     a significand and an exponent
+ *     a significand and an exponent. This conversion is <b>not</b> supported
+ *     for the {@code BigDecimal} type despite the latter's being in the
+ *     <i>floating point</i> argument category.
  *
  * <tr><td valign="top">{@code 't'}, {@code 'T'}
  *     <td valign="top"> date/time
@@ -617,12 +626,11 @@
  * <p> For general argument types, the precision is the maximum number of
  * characters to be written to the output.
  *
- * <p> For the floating-point conversions {@code 'e'}, {@code 'E'}, and
- * {@code 'f'} the precision is the number of digits after the decimal
- * separator.  If the conversion is {@code 'g'} or {@code 'G'}, then the
+ * <p> For the floating-point conversions {@code 'a'}, {@code 'A'}, {@code 'e'},
+ * {@code 'E'}, and {@code 'f'} the precision is the number of digits after the
+ * radix point.  If the conversion is {@code 'g'} or {@code 'G'}, then the
  * precision is the total number of digits in the resulting magnitude after
- * rounding.  If the conversion is {@code 'a'} or {@code 'A'}, then the
- * precision must not be specified.
+ * rounding.
  *
  * <p> For character, integral, and date/time argument types and the percent
  * and line separator conversions, the precision is not applicable; if a
@@ -832,7 +840,7 @@
  *
  * <p> Numeric types will be formatted according to the following algorithm:
  *
- * <p><b><a name="l10n algorithm"> Number Localization Algorithm</a></b>
+ * <p><b><a name="L10nAlgorithm"> Number Localization Algorithm</a></b>
  *
  * <p> After digits are obtained for the integer part, fractional part, and
  * exponent (as appropriate for the data type), the following transformation
@@ -851,7 +859,7 @@
  * substituted.
  *
  * <li> If the {@code ','} (<tt>'&#92;u002c'</tt>)
- * <a name="l10n group">flag</a> is given, then the locale-specific {@linkplain
+ * <a name="L10nGroup">flag</a> is given, then the locale-specific {@linkplain
  * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
  * inserted by scanning the integer part of the string from least significant
  * to most significant digits and inserting a separator at intervals defined by
@@ -891,9 +899,9 @@
  * <table cellpadding=5 summary="IntConv">
  *
  * <tr><td valign="top"> {@code 'd'}
- *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
  *     <td> Formats the argument as a decimal integer. The <a
- *     href="#l10n algorithm">localization algorithm</a> is applied.
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
  *
  *     <p> If the {@code '0'} flag is given and the value is negative, then
  *     the zero padding will occur after the sign.
@@ -919,7 +927,7 @@
  *     <p> If the {@code '0'} flag is given then the output will be padded
  *     with leading zeros to the field width following any indication of sign.
  *
- *     <p> If {@code '('}, {@code '+'}, '&nbsp&nbsp;', or {@code ','} flags
+ *     <p> If {@code '('}, {@code '+'}, '&nbsp;&nbsp;', or {@code ','} flags
  *     are given then a {@link FormatFlagsConversionMismatchException} will be
  *     thrown.
  *
@@ -1002,7 +1010,7 @@
  *     <td valign="top"> <tt>'&#92;u002c'</tt>
  *     <td> Requires the output to include the locale-specific {@linkplain
  *     java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
- *     described in the <a href="#l10n group">"group" section</a> of the
+ *     described in the <a href="#L10nGroup">"group" section</a> of the
  *     localization algorithm.
  *
  * <tr><td valign="top"> {@code '('}
@@ -1049,9 +1057,9 @@
  * <table cellpadding=5 summary="BIntConv">
  *
  * <tr><td valign="top"> {@code 'd'}
- *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
  *     <td> Requires the output to be formatted as a decimal integer. The <a
- *     href="#l10n algorithm">localization algorithm</a> is applied.
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
  *
  *     <p> If the {@code '#'} flag is given {@link
  *     FormatFlagsConversionMismatchException} will be thrown.
@@ -1146,7 +1154,7 @@
  *     <td valign="top"> <tt>'&#92;u0065'</tt>
  *     <td> Requires the output to be formatted using <a
  *     name="scientific">computerized scientific notation</a>.  The <a
- *     href="#l10n algorithm">localization algorithm</a> is applied.
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
  *
  *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
  *
@@ -1159,7 +1167,7 @@
  *
  *     <p> Otherwise, the result is a string that represents the sign and
  *     magnitude (absolute value) of the argument.  The formatting of the sign
- *     is described in the <a href="#l10n algorithm">localization
+ *     is described in the <a href="#L10nAlgorithm">localization
  *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
  *     value.
  *
@@ -1201,7 +1209,7 @@
  * <tr><td valign="top"> {@code 'g'}
  *     <td valign="top"> <tt>'&#92;u0067'</tt>
  *     <td> Requires the output to be formatted in general scientific notation
- *     as described below. The <a href="#l10n algorithm">localization
+ *     as described below. The <a href="#L10nAlgorithm">localization
  *     algorithm</a> is applied.
  *
  *     <p> After rounding for the precision, the formatting of the resulting
@@ -1230,12 +1238,12 @@
  * <tr><td valign="top"> {@code 'f'}
  *     <td valign="top"> <tt>'&#92;u0066'</tt>
  *     <td> Requires the output to be formatted using <a name="decimal">decimal
- *     format</a>.  The <a href="#l10n algorithm">localization algorithm</a> is
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
  *     applied.
  *
  *     <p> The result is a string that represents the sign and magnitude
  *     (absolute value) of the argument.  The formatting of the sign is
- *     described in the <a href="#l10n algorithm">localization
+ *     described in the <a href="#L10nAlgorithm">localization
  *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
  *     value.
  *
@@ -1291,14 +1299,21 @@
  *     of the significand as a fraction.  The exponent is represented by
  *     {@code 'p'} (<tt>'&#92;u0070'</tt>) followed by a decimal string of the
  *     unbiased exponent as if produced by invoking {@link
- *     Integer#toString(int) Integer.toString} on the exponent value.
+ *     Integer#toString(int) Integer.toString} on the exponent value.  If the
+ *     precision is specified, the value is rounded to the given number of
+ *     hexadecimal digits.
  *
  *     <li> If <i>m</i> is a {@code double} value with a subnormal
- *     representation then the significand is represented by the characters
- *     {@code '0x0.'} followed by the hexadecimal representation of the rest
- *     of the significand as a fraction.  The exponent is represented by
- *     {@code 'p-1022'}.  Note that there must be at least one nonzero digit
- *     in a subnormal significand.
+ *     representation then, unless the precision is specified to be in the range
+ *     1 through 12, inclusive, the significand is represented by the characters
+ *     {@code '0x0.'} followed by the hexadecimal representation of the rest of
+ *     the significand as a fraction, and the exponent represented by
+ *     {@code 'p-1022'}.  If the precision is in the interval
+ *     [1,&nbsp;12], the subnormal value is normalized such that it
+ *     begins with the characters {@code '0x1.'}, rounded to the number of
+ *     hexadecimal digits of precision, and the exponent adjusted
+ *     accordingly.  Note that there must be at least one nonzero digit in a
+ *     subnormal significand.
  *
  *     </ul>
  *
@@ -1361,7 +1376,7 @@
  * {@code 1}.
  *
  * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision
- * is the number of hexadecimal digits after the decimal separator.  If the
+ * is the number of hexadecimal digits after the radix point.  If the
  * precision is not provided, then all of the digits as returned by {@link
  * Double#toHexString(double)} will be output.
  *
@@ -1376,7 +1391,7 @@
  *     <td valign="top"> <tt>'&#92;u0065'</tt>
  *     <td> Requires the output to be formatted using <a
  *     name="bscientific">computerized scientific notation</a>.  The <a
- *     href="#l10n algorithm">localization algorithm</a> is applied.
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
  *
  *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
  *
@@ -1385,7 +1400,7 @@
  *
  *     <p> Otherwise, the result is a string that represents the sign and
  *     magnitude (absolute value) of the argument.  The formatting of the sign
- *     is described in the <a href="#l10n algorithm">localization
+ *     is described in the <a href="#L10nAlgorithm">localization
  *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
  *     value.
  *
@@ -1422,7 +1437,7 @@
  * <tr><td valign="top"> {@code 'g'}
  *     <td valign="top"> <tt>'&#92;u0067'</tt>
  *     <td> Requires the output to be formatted in general scientific notation
- *     as described below. The <a href="#l10n algorithm">localization
+ *     as described below. The <a href="#L10nAlgorithm">localization
  *     algorithm</a> is applied.
  *
  *     <p> After rounding for the precision, the formatting of the resulting
@@ -1451,12 +1466,12 @@
  * <tr><td valign="top"> {@code 'f'}
  *     <td valign="top"> <tt>'&#92;u0066'</tt>
  *     <td> Requires the output to be formatted using <a name="bdecimal">decimal
- *     format</a>.  The <a href="#l10n algorithm">localization algorithm</a> is
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
  *     applied.
  *
  *     <p> The result is a string that represents the sign and magnitude
  *     (absolute value) of the argument.  The formatting of the sign is
- *     described in the <a href="#l10n algorithm">localization
+ *     described in the <a href="#L10nAlgorithm">localization
  *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
  *     value.
  *
@@ -1492,7 +1507,7 @@
  * <h4><a name="ddt">Date/Time</a></h4>
  *
  * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
- * Calendar}, and {@link Date}.
+ * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
  *
  * <table cellpadding=5 summary="DTConv">
  *
@@ -1715,7 +1730,7 @@
  * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
  * FormatFlagsConversionMismatchException} will be thrown.
  *
- * <p> The <a name="dtWidth">width</a> is the minimum number of characters to
+ * <p> The width is the minimum number of characters to
  * be written to the output.  If the length of the converted value is less than
  * the {@code width} then the output will be padded by spaces
  * (<tt>'&#92;u0020'</tt>) until the total number of characters equals width.
@@ -1735,7 +1750,7 @@
  * <tr><td valign="top">{@code '%'}
  *     <td> The result is a literal {@code '%'} (<tt>'&#92;u0025'</tt>)
  *
- * <p> The <a name="dtWidth">width</a> is the minimum number of characters to
+ * <p> The width is the minimum number of characters to
  * be written to the output including the {@code '%'}.  If the length of the
  * converted value is less than the {@code width} then the output will be
  * padded by spaces (<tt>'&#92;u0020'</tt>) until the total number of
@@ -1894,7 +1909,8 @@
      * which may be retrieved by invoking {@link #out out()} and whose
      * current content may be converted into a string by invoking {@link
      * #toString toString()}.  The locale used is the {@linkplain
-     * Locale#getDefault() default locale} for this instance of the Java
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
      * virtual machine.
      */
     public Formatter() {
@@ -1904,8 +1920,10 @@
     /**
      * Constructs a new formatter with the specified destination.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault() default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  a
      *         Destination for the formatted output.  If {@code a} is
@@ -1955,8 +1973,10 @@
      * java.nio.charset.Charset#defaultCharset() default charset} for this
      * instance of the Java virtual machine.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault() default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  fileName
      *         The name of the file to use as the destination of this
@@ -1983,8 +2003,10 @@
     /**
      * Constructs a new formatter with the specified file name and charset.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  fileName
      *         The name of the file to use as the destination of this
@@ -2062,8 +2084,10 @@
      * java.nio.charset.Charset#defaultCharset() default charset} for this
      * instance of the Java virtual machine.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault() default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  file
      *         The file to use as the destination of this formatter.  If the
@@ -2090,8 +2114,10 @@
     /**
      * Constructs a new formatter with the specified file and charset.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  file
      *         The file to use as the destination of this formatter.  If the
@@ -2165,8 +2191,10 @@
     /**
      * Constructs a new formatter with the specified print stream.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault() default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * <p> Characters are written to the given {@link java.io.PrintStream
      * PrintStream} object and are therefore encoded using that object's
@@ -2187,8 +2215,10 @@
      * java.nio.charset.Charset#defaultCharset() default charset} for this
      * instance of the Java virtual machine.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault() default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  os
      *         The output stream to use as the destination of this formatter.
@@ -2203,8 +2233,10 @@
      * Constructs a new formatter with the specified output stream and
      * charset.
      *
-     * <p> The locale used is the {@linkplain Locale#getDefault default
-     * locale} for this instance of the Java virtual machine.
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
      *
      * @param  os
      *         The output stream to use as the destination of this formatter.
@@ -2504,6 +2536,7 @@
         return this;
     }
 
+    // Android-changed BEGIN: changed parse() to manual parsing instead of regex.
     /**
      * Finds format specifiers in the format string.
      */
@@ -2633,6 +2666,7 @@
             return cursor;
         }
     }
+    // Android-changed END: changed parse() to manual parsing instead of regex.
 
     private interface FormatString {
         int index();
@@ -2649,7 +2683,20 @@
         public String toString() { return s; }
     }
 
-    public enum BigDecimalLayoutForm { SCIENTIFIC, DECIMAL_FLOAT };
+    /**
+     * Enum for {@code BigDecimal} formatting.
+     */
+    public enum BigDecimalLayoutForm {
+        /**
+         * Format the {@code BigDecimal} in computerized scientific notation.
+         */
+        SCIENTIFIC,
+
+        /**
+         * Format the {@code BigDecimal} as a decimal number.
+         */
+        DECIMAL_FLOAT
+    };
 
     private class FormatSpecifier implements FormatString {
         private int index = -1;
@@ -2662,6 +2709,7 @@
         private int index(String s) {
             if (s != null) {
                 try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
                     index = Integer.parseInt(s);
                 } catch (NumberFormatException x) {
                     assert(false);
@@ -2741,6 +2789,7 @@
             return c;
         }
 
+        // Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
         FormatSpecifier(String indexStr, String flagsStr, String widthStr,
                         String precisionStr, String tTStr, String convStr) {
             int idx = 1;
@@ -2865,8 +2914,11 @@
                 cal = Calendar.getInstance(l == null ? Locale.US : l);
                 cal.setTime((Date)arg);
             } else if (arg instanceof Calendar) {
-                cal = (Calendar) ((Calendar)arg).clone();
+                cal = (Calendar) ((Calendar) arg).clone();
                 cal.setLenient(true);
+            } else if (arg instanceof TemporalAccessor) {
+                print((TemporalAccessor) arg, c, l);
+                return;
             } else {
                 failConversion(c, arg);
             }
@@ -2945,7 +2997,7 @@
             if (precision != -1 && precision < s.length())
                 s = s.substring(0, precision);
             if (f.contains(Flags.UPPERCASE)) {
-                // Always uppercase strings according to the provided locale.
+                // Android-changed: Use provided locale instead of default, if it is non-null.
                 s = s.toUpperCase(l != null ? l : Locale.getDefault());
             }
             a.append(justify(s));
@@ -3299,8 +3351,8 @@
                 int prec = (precision == -1 ? 6 : precision);
 
                 FormattedFloatingDecimal fd
-                    = FormattedFloatingDecimal.valueOf(value, prec,
-                        FormattedFloatingDecimal.Form.SCIENTIFIC);
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.SCIENTIFIC);
 
                 char[] mant = addZeros(fd.getMantissa(), prec);
 
@@ -3317,6 +3369,7 @@
                     newW = adjustWidth(width - exp.length - 1, f, neg);
                 localizedMagnitude(sb, mant, f, newW, l);
 
+                // Android-changed: Use localized exponent separator for %e.
                 Locale separatorLocale = (l != null) ? l : Locale.getDefault();
                 LocaleData localeData = LocaleData.get(separatorLocale);
                 sb.append(f.contains(Flags.UPPERCASE) ?
@@ -3439,30 +3492,6 @@
             }
         }
 
-        private char[] mantissa(char[] v, int len) {
-            int i;
-            for (i = 0; i < len; i++) {
-                if (v[i] == 'e')
-                    break;
-            }
-            char[] tmp = new char[i];
-            System.arraycopy(v, 0, tmp, 0, i);
-            return tmp;
-        }
-
-        private char[] exponent(char[] v, int len) {
-            int i;
-            for (i = len - 1; i >= 0; i--) {
-                if (v[i] == 'e')
-                    break;
-            }
-            if (i == -1)
-                return null;
-            char[] tmp = new char[len - i - 1];
-            System.arraycopy(v, i + 1, tmp, 0, len - i - 1);
-            return tmp;
-        }
-
         // Add zeros to the requested precision.
         private char[] addZeros(char[] v, int prec) {
             // Look for the dot.  If we don't find one, the we'll need to add
@@ -3505,24 +3534,24 @@
         // Method assumes that d > 0.
         private String hexDouble(double d, int prec) {
             // Let Double.toHexString handle simple cases
-            if(!FpUtils.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13)
+            if(!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13)
                 // remove "0x"
                 return Double.toHexString(d).substring(2);
             else {
                 assert(prec >= 1 && prec <= 12);
 
-                int exponent  = FpUtils.getExponent(d);
+                int exponent  = Math.getExponent(d);
                 boolean subnormal
                     = (exponent == DoubleConsts.MIN_EXPONENT - 1);
 
                 // If this is subnormal input so normalize (could be faster to
                 // do as integer operation).
                 if (subnormal) {
-                    scaleUp = FpUtils.scalb(1.0, 54);
+                    scaleUp = Math.scalb(1.0, 54);
                     d *= scaleUp;
                     // Calculate the exponent.  This is not just exponent + 54
                     // since the former is not the normalized exponent.
-                    exponent = FpUtils.getExponent(d);
+                    exponent = Math.getExponent(d);
                     assert exponent >= DoubleConsts.MIN_EXPONENT &&
                         exponent <= DoubleConsts.MAX_EXPONENT: exponent;
                 }
@@ -3916,7 +3945,6 @@
                                  Locale l)
             throws IOException
         {
-            assert(width == -1);
             if (sb == null)
                 sb = new StringBuilder();
             switch (c) {
@@ -4122,6 +4150,242 @@
             return sb;
         }
 
+        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+                                 Locale l) throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            try {
+                switch (c) {
+                case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_0:      {  // 'I' (01 - 12)
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.MINUTE:      { // 'M' (00 - 59)
+                    int i = t.get(ChronoField.MINUTE_OF_HOUR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    break;
+                }
+                case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
+                             t.getLong(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.AM_PM:       { // 'p' (am or pm)
+                    // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                    String[] ampm = { "AM", "PM" };
+                    if (l != null && l != Locale.US) {
+                        DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                        ampm = dfs.getAmPmStrings();
+                    }
+                    String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
+                    sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                    int i = t.get(ChronoField.SECOND_OF_MINUTE);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                    int i = t.get(ChronoField.OFFSET_SECONDS);
+                    boolean neg = i < 0;
+                    sb.append(neg ? '-' : '+');
+                    if (neg)
+                        i = -i;
+                    int min = i / 60;
+                    // combine minute and hour into a single integer
+                    int offset = (min / 60) * 100 + (min % 60);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    break;
+                }
+                case DateTime.ZONE:        { // 'Z' (symbol)
+                    ZoneId zid = t.query(TemporalQueries.zone());
+                    if (zid == null) {
+                        throw new IllegalFormatConversionException(c, t.getClass());
+                    }
+                    if (!(zid instanceof ZoneOffset) &&
+                        t.isSupported(ChronoField.INSTANT_SECONDS)) {
+                        Instant instant = Instant.from(t);
+                        sb.append(TimeZone.getTimeZone(zid.getId())
+                                          .getDisplayName(zid.getRules().isDaylightSavings(instant),
+                                                          TimeZone.SHORT,
+                                                          (l == null) ? Locale.US : l));
+                        break;
+                    }
+                    sb.append(zid.getId());
+                    break;
+                }
+                // Date
+                case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+                case DateTime.NAME_OF_DAY:          { // 'A'
+                    int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_DAY)
+                        sb.append(dfs.getWeekdays()[i]);
+                    else
+                        sb.append(dfs.getShortWeekdays()[i]);
+                    break;
+                }
+                case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+                case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+                case DateTime.NAME_OF_MONTH:        { // 'B'
+                    int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_MONTH)
+                        sb.append(dfs.getMonths()[i]);
+                    else
+                        sb.append(dfs.getShortMonths()[i]);
+                    break;
+                }
+                case DateTime.CENTURY:                // 'C' (00 - 99)
+                case DateTime.YEAR_2:                 // 'y' (00 - 99)
+                case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                    int i = t.get(ChronoField.YEAR_OF_ERA);
+                    int size = 2;
+                    switch (c) {
+                    case DateTime.CENTURY:
+                        i /= 100;
+                        break;
+                    case DateTime.YEAR_2:
+                        i %= 100;
+                        break;
+                    case DateTime.YEAR_4:
+                        size = 4;
+                        break;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    break;
+                }
+                case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+                case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                    int i = t.get(ChronoField.DAY_OF_MONTH);
+                    Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                                   ? Flags.ZERO_PAD
+                                   : Flags.NONE);
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                    int i = t.get(ChronoField.DAY_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MONTH:                { // 'm' (01 - 12)
+                    int i = t.get(ChronoField.MONTH_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+
+                // Composites
+                case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+                case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l);
+                    if (c == DateTime.TIME) {
+                        sb.append(sep);
+                        print(sb, t, DateTime.SECOND, l);
+                    }
+                    break;
+                }
+                case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l).append(sep);
+                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    // this may be in wrong place for some locales
+                    StringBuilder tsb = new StringBuilder();
+                    print(tsb, t, DateTime.AM_PM, l);
+                    sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                    char sep = ' ';
+                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.TIME, l).append(sep);
+                    print(sb, t, DateTime.ZONE, l).append(sep);
+                    print(sb, t, DateTime.YEAR_4, l);
+                    break;
+                }
+                case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                    char sep = '/';
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.YEAR_2, l);
+                    break;
+                }
+                case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                    char sep = '-';
+                    print(sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    break;
+                }
+                default:
+                    assert false;
+                }
+            } catch (DateTimeException x) {
+                throw new IllegalFormatConversionException(c, t.getClass());
+            }
+            return sb;
+        }
+
         // -- Methods to support throwing exceptions --
 
         private void failMismatch(Flags f, char c) {
diff --git a/ojluni/src/main/java/sun/net/InetAddressCachePolicy.java b/ojluni/src/main/java/sun/net/InetAddressCachePolicy.java
deleted file mode 100644
index f22e435..0000000
--- a/ojluni/src/main/java/sun/net/InetAddressCachePolicy.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net;
-
-import java.security.PrivilegedAction;
-import java.security.Security;
-
-public final class InetAddressCachePolicy {
-
-    // Controls the cache policy for successful lookups only
-    private static final String cachePolicyProp = "networkaddress.cache.ttl";
-    private static final String cachePolicyPropFallback =
-        "sun.net.inetaddr.ttl";
-
-    // Controls the cache policy for negative lookups only
-    private static final String negativeCachePolicyProp =
-        "networkaddress.cache.negative.ttl";
-    private static final String negativeCachePolicyPropFallback =
-        "sun.net.inetaddr.negative.ttl";
-
-    public static final int FOREVER = -1;
-    public static final int NEVER = 0;
-
-    /* default value for positive lookups */
-    //  ----- BEGIN android -----
-    //public static final int DEFAULT_POSITIVE = 30;
-    // The TTL for the android Java-level cache is short, just 2s.
-    public static final int DEFAULT_POSITIVE = 2;
-    //  ----- END android -----
-
-    /* The Java-level namelookup cache policy for successful lookups:
-     *
-     * -1: caching forever
-     * any positive value: the number of seconds to cache an address for
-     *
-     * default value is forever (FOREVER), as we let the platform do the
-     * caching. For security reasons, this caching is made forever when
-     * a security manager is set.
-     */
-    private static int cachePolicy = FOREVER;
-
-    /* The Java-level namelookup cache policy for negative lookups:
-     *
-     * -1: caching forever
-     * any positive value: the number of seconds to cache an address for
-     *
-     * default value is 0. It can be set to some other value for
-     * performance reasons.
-     */
-    private static int negativeCachePolicy = NEVER;
-
-    /*
-     * Whether or not the cache policy for successful lookups was set
-     * using a property (cmd line).
-     */
-    private static boolean propertySet;
-
-    /*
-     * Whether or not the cache policy for negative lookups was set
-     * using a property (cmd line).
-     */
-    private static boolean propertyNegativeSet;
-
-    /*
-     * Initialize
-     */
-    static {
-        Integer tmp = null;
-
-        try {
-            tmp = new Integer(
-              java.security.AccessController.doPrivileged (
-                new PrivilegedAction<String>() {
-                  public String run() {
-                      return Security.getProperty(cachePolicyProp);
-                  }
-              }));
-        } catch (NumberFormatException e) {
-            // ignore
-        }
-        if (tmp != null) {
-            cachePolicy = tmp.intValue();
-            if (cachePolicy < 0) {
-                cachePolicy = FOREVER;
-            }
-            propertySet = true;
-        } else {
-            tmp = java.security.AccessController.doPrivileged
-                (new sun.security.action.GetIntegerAction(cachePolicyPropFallback));
-            if (tmp != null) {
-                cachePolicy = tmp.intValue();
-                if (cachePolicy < 0) {
-                    cachePolicy = FOREVER;
-                }
-                propertySet = true;
-            } else {
-                /* No properties defined for positive caching. If there is no
-                 * security manager then use the default positive cache value.
-                 */
-                if (System.getSecurityManager() == null) {
-                    cachePolicy = DEFAULT_POSITIVE;
-                }
-            }
-        }
-
-        try {
-            tmp = new Integer(
-              java.security.AccessController.doPrivileged (
-                new PrivilegedAction<String>() {
-                  public String run() {
-                      return Security.getProperty(negativeCachePolicyProp);
-                  }
-              }));
-        } catch (NumberFormatException e) {
-            // ignore
-        }
-
-        if (tmp != null) {
-            negativeCachePolicy = tmp.intValue();
-            if (negativeCachePolicy < 0) {
-                negativeCachePolicy = FOREVER;
-            }
-            propertyNegativeSet = true;
-        } else {
-            tmp = java.security.AccessController.doPrivileged
-                (new sun.security.action.GetIntegerAction(negativeCachePolicyPropFallback));
-            if (tmp != null) {
-                negativeCachePolicy = tmp.intValue();
-                if (negativeCachePolicy < 0) {
-                    negativeCachePolicy = FOREVER;
-                }
-                propertyNegativeSet = true;
-            }
-        }
-    }
-
-    public static synchronized int get() {
-        return cachePolicy;
-    }
-
-    public static synchronized int getNegative() {
-        return negativeCachePolicy;
-    }
-
-    /**
-     * Sets the cache policy for successful lookups if the user has not
-     * already specified a cache policy for it using a
-     * command-property.
-     * @param newPolicy the value in seconds for how long the lookup
-     * should be cached
-     */
-    public static synchronized void setIfNotSet(int newPolicy) {
-        /*
-         * When setting the new value we may want to signal that the
-         * cache should be flushed, though this doesn't seem strictly
-         * necessary.
-         */
-        if (!propertySet) {
-            checkValue(newPolicy, cachePolicy);
-            cachePolicy = newPolicy;
-        }
-    }
-
-    /**
-     * Sets the cache policy for negative lookups if the user has not
-     * already specified a cache policy for it using a
-     * command-property.
-     * @param newPolicy the value in seconds for how long the lookup
-     * should be cached
-     */
-    public static synchronized void setNegativeIfNotSet(int newPolicy) {
-        /*
-         * When setting the new value we may want to signal that the
-         * cache should be flushed, though this doesn't seem strictly
-         * necessary.
-         */
-        if (!propertyNegativeSet) {
-            // Negative caching does not seem to have any security
-            // implications.
-            // checkValue(newPolicy, negativeCachePolicy);
-            negativeCachePolicy = newPolicy;
-        }
-    }
-
-    private static void checkValue(int newPolicy, int oldPolicy) {
-        /*
-         * If malicious code gets a hold of this method, prevent
-         * setting the cache policy to something laxer or some
-         * invalid negative value.
-         */
-        if (newPolicy == FOREVER)
-            return;
-
-        if ((oldPolicy == FOREVER) ||
-            (newPolicy < oldPolicy) ||
-            (newPolicy < FOREVER)) {
-
-            throw new
-                SecurityException("can't make InetAddress cache more lax");
-        }
-    }
-}
diff --git a/ojluni/src/main/java/sun/net/RegisteredDomain.java b/ojluni/src/main/java/sun/net/RegisteredDomain.java
deleted file mode 100644
index 49c67c2..0000000
--- a/ojluni/src/main/java/sun/net/RegisteredDomain.java
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * The naming tables listed below were gathered from publicly available data such as
- * the subdomain registration websites listed for each top-level domain by the Internet
- * Assigned Numbers Authority and the website of the Internet Corporation for Assigned Names
- * and Numbers as well as Wikipedia.
- */
-
-public class RegisteredDomain {
-
-// XX.AA
-private static Set<String> top1Set = new HashSet<String>(Arrays.asList("asia", "biz", "cat", "coop",
-        "edu", "info", "gov", "jobs", "travel", "am", "aq", "ax", "cc", "cf", "cg", "ch", "cv", "cz",
-        "de", "dj", "dk", "fm", "fo", "ga", "gd", "gf", "gl", "gm", "gq", "gs", "gw", "hm",
-        "li", "lu", "md", "mh", "mil", "mobi", "mq", "ms", "ms", "ne", "nl", "nu", "si",
-        "sm", "sr", "su", "tc", "td", "tf", "tg", "tk", "tm", "tv", "va", "vg",
-        /* ae */ "xn--mgbaam7a8h",      /* cn s */      "xn--fiqs8s",        /* cn t */ "xn--fiqz9s",
-        /* eg */ "xn--wgbh1c",          /* hk */        "xn--j6w193g",       /* jo */   "xn--mgbayh7gpa",
-        /* lk */ "xn--fzc2c9e2c",       /* ps */        "xn--ygbi2ammx",     /* ru */   "xn--p1ai",
-        /* qa */ "xn--wgbl6a",          /* sa */        "xn--mgberp4a5d4ar", /* sg */   "xn--yfro4i67o",
-        /* th */ "xn--o3cw4h",          /* tn */        "xn--pgbs0dh",       /* tw s */ "xn--kpry57d",
-        /* tw */ "xn--kprw13d",         /* sg tamil */  "xn--clchc0ea0b2g2a9gcd"));
-
-// common pattern: XX.AA or XX.GOV.AA
-private static Set<String> top2Set = new HashSet<String>(Arrays.asList("as", "bf", "cd", "cx",
-        "ie", "lt", "mr", "tl"));
-
-// common pattern: XX.AA or XX.COM.AA or XX.EDU.AA or XX.NET.AA or XX.ORG.AA or XX.GOV.AA
-private static Set<String> top4Set = new HashSet<String>(Arrays.asList("af", "bm", "bs", "bt",
-        "bz", "dm", "ky", "lb", "lr", "mo", "sc", "sl", "ws"));
-
-// AA or less than 3 other XX.BB.AA possible matches
-private static Set<String> top3Set = new HashSet<String>(Arrays.asList("ad", "aw", "be", "bw",
-        "cl", "fi", "int", "io", "mc"));
-
-// AA.UK exceptions
-private static Set<String> ukSet = new HashSet<String>(Arrays.asList( "bl", "british-library",
-        "jet", "nhs", "nls", "parliament", "mod", "police"));
-
-// AA.AR exceptions
-private static Set<String> arSet = new HashSet<String>(Arrays.asList( "argentina", "educ",
-        "gobiernoelectronico", "nic", "promocion", "retina", "uba"));
-
-// AA.OM exceptions
-private static Set<String> omSet = new HashSet<String>(Arrays.asList("mediaphone", "nawrastelecom",
-        "nawras", "omanmobile", "omanpost", "omantel", "rakpetroleum", "siemens", "songfest",
-        "statecouncil", "shura", "peie", "omran", "omnic", "omanet", "oman", "muriya", "kom"));
-
-// any XX.BB.AA
-private static Set<String> top5Set = new HashSet<String>(Arrays.asList("au", "arpa", "bd", "bn", "ck",
-         "cy", "er", "et", "fj", "fk", "gt", "gu", "il", "jm", "ke", "kh", "kw",
-         "mm", "mt", "mz", "ni", "np", "nz", "pg", "sb", "sv", "tz", "uy", "ve", "ye",
-         "za", "zm", "zw"));
-
-// XX.CC.BB.JP
-private static Set<String> jpSet = new HashSet<String>(Arrays.asList("aichi", "akita", "aomori",
-        "chiba", "ehime", "fukui", "fukuoka", "fukushima", "gifu", "gunma", "hiroshima", "hokkaido",
-        "hyogo", "ibaraki", "ishikawa", "iwate", "kagawa", "kagoshima", "kanagawa", "kawasaki",
-        "kitakyushu", "kobe", "kochi", "kumamoto", "kyoto", "mie", "miyagi", "miyazaki", "nagano",
-        "nagasaki", "nagoya", "nara", "niigata", "oita", "okayama", "okinawa", "osaka", "saga",
-        "saitama", "sapporo", "sendai", "shiga", "shimane", "shizuoka", "tochigi", "tokushima",
-        "tokyo", "tottori", "toyama", "wakayama", "yamagata", "yamaguchi", "yamanashi", "yokohama"));
-
-// CC.BB.JP exceptions
-private static Set<String> jp2Set = new HashSet<String>(Arrays.asList("metro.tokyo.jp",
-        "pref.aichi.jp", "pref.akita.jp", "pref.aomori.jp", "pref.chiba.jp", "pref.ehime.jp",
-        "pref.fukui.jp", "pref.fukuoka.jp", "pref.fukushima.jp", "pref.gifu.jp", "pref.gunma.jp",
-        "pref.hiroshima.jp", "pref.hokkaido.jp", "pref.hyogo.jp", "pref.ibaraki.jp", "pref.ishikawa.jp",
-        "pref.iwate.jp", "pref.kagawa.jp", "pref.kagoshima.jp", "pref.kanagawa.jp", "pref.kochi.jp",
-        "pref.kumamoto.jp", "pref.kyoto.jp", "pref.mie.jp", "pref.miyagi.jp", "pref.miyazaki.jp",
-        "pref.nagano.jp", "pref.nagasaki.jp", "pref.nara.jp", "pref.niigata.jp", "pref.oita.jp",
-        "pref.okayama.jp", "pref.okinawa.jp", "pref.osaka.jp", "pref.saga.jp", "pref.saitama.jp",
-        "pref.shiga.jp", "pref.shimane.jp", "pref.shizuoka.jp", "pref.tochigi.jp", "pref.tokushima.jp",
-        "pref.tottori.jp", "pref.toyama.jp", "pref.wakayama.jp", "pref.yamagata.jp", "pref.yamaguchi.jp",
-        "pref.yamanashi.jp", "city.chiba.jp", "city.fukuoka.jp", "city.hamamatsu.jp", "city.hiroshima.jp", "city.kawasaki.jp",
-        "city.kitakyushu.jp", "city.kobe.jp", "city.kyoto.jp", "city.nagoya.jp", "city.niigata.jp",
-        "city.okayama.jp", "city.osaka.jp", "city.sagamihara.jp", "city.saitama.jp", "city.sapporo.jp", "city.sendai.jp",
-        "city.shizuoka.jp", "city.yokohama.jp"));
-
-private static Set<String>  usStateSet = new HashSet<String>(Arrays.asList("ak",
-                "al", "ar", "as", "az", "ca", "co", "ct", "dc", "de", "fl", "ga", "gu", "hi", "ia",
-                "id", "il", "in", "ks", "ky", "la", "ma", "md", "me", "mi", "mn", "mo", "ms", "mt",
-                "nc", "nd", "ne", "nh", "nj", "nm", "nv", "ny", "oh", "ok", "or", "pa", "pr", "ri",
-                "sc", "sd", "tn", "tx", "ut", "vi", "vt", "va", "wa", "wi", "wv", "wy"));
-
-private static Set<String>  usSubStateSet = new HashSet<String>(Arrays.asList("state",
-                "lib", "k12", "cc", "tec", "gen", "cog", "mus", "dst"));
-
-private static Map<String,Set> topMap = new HashMap<String,Set>();
-private static Map<String,Set> top3Map = new HashMap<String,Set>();
-
-static {
-    /*
-     * XX.AA or XX.BB.AA
-     */
-    topMap.put("ac", new HashSet<String>(Arrays.asList("com", "co", "edu", "gov", "net", "mil", "org")));
-    topMap.put("ae", new HashSet<String>(Arrays.asList("co", "net", "org", "sch", "ac", "gov", "mil")));
-    topMap.put("aero", new HashSet<String>(Arrays.asList("accident-investigation",
-                "accident-prevention", "aerobatic", "aeroclub", "aerodrome", "agents", "aircraft",
-                "airline", "airport", "air-surveillance", "airtraffic", "air-traffic-control",
-                "ambulance", "amusement", "association", "author", "ballooning", "broker", "caa",
-                "cargo", "catering", "certification", "championship", "charter", "civilaviation",
-                "club", "conference", "consultant", "consulting", "control", "council", "crew",
-                "design", "dgca", "educator", "emergency", "engine", "engineer", "entertainment",
-                "equipment", "exchange", "express", "federation", "flight", "freight", "fuel",
-                "gliding", "government", "groundhandling", "group", "hanggliding", "homebuilt",
-                "insurance", "journal", "journalist", "leasing", "logistics", "magazine",
-                "maintenance", "marketplace", "media", "microlight", "modelling", "navigation",
-                "parachuting", "paragliding", "passenger-association", "pilot", "press", "production",
-                "recreation", "repbody", "res", "research", "rotorcraft", "safety", "scientist",
-                "services", "show", "skydiving", "software", "student", "taxi", "trader", "trading",
-                "trainer", "union", "workinggroup", "works" )));
-    topMap.put( "ag", new HashSet<String>(Arrays.asList("com", "org", "net", "co", "nom")));
-    topMap.put( "ai", new HashSet<String>(Arrays.asList("off", "com", "net", "org")));
-    topMap.put( "al", new HashSet<String>(Arrays.asList("com", "edu", "gov", "mil", "net", "org")));
-    topMap.put( "an", new HashSet<String>(Arrays.asList("com")));
-    topMap.put( "ao", new HashSet<String>(Arrays.asList("ed", "gv", "og", "co", "pb", "it")));
-    topMap.put( "at", new HashSet<String>(Arrays.asList("ac", "co", "gv", "or", "biz", "info", "priv")));
-    topMap.put( "az", new HashSet<String>(Arrays.asList("com", "net", "int", "gov", "org", "edu", "info",
-                "pp", "mil", "name", "biz")));
-    topMap.put( "ba", new HashSet<String>(Arrays.asList("org", "net", "edu", "gov", "mil", "unbi",
-                "unmo", "unsa", "untz", "unze", "co", "com", "rs")));
-    topMap.put( "bb", new HashSet<String>(Arrays.asList("biz", "com", "edu", "gov", "info", "net", "org",
-                "store")));
-    topMap.put( "bg", new HashSet<String>(Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
-                "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1",
-                "2", "3", "4", "5", "6", "7", "8", "9")));
-    topMap.put( "bh", new HashSet<String>(Arrays.asList("com", "info", "cc", "edu", "biz", "net",
-                "org", "gov")));
-    topMap.put( "bi", new HashSet<String>(Arrays.asList("co", "com", "edu", "gov", "info", "or", "org")));
-    topMap.put( "bj", new HashSet<String>(Arrays.asList("asso", "barreau", "com", "edu", "gouv", "gov", "mil")));
-    topMap.put( "bo", new HashSet<String>(Arrays.asList("com", "edu", "gov", "gob", "int", "org", "net",
-                 "mil", "tv")));
-    topMap.put( "br", new HashSet<String>(Arrays.asList("adm", "adv", "agr", "am", "arq", "art", "ato",
-                "b", "bio", "blog", "bmd", "cim", "cng", "cnt", "com", "coop", "ecn", "edu", "emp", "eng",
-                "esp", "etc", "eti", "far", "flog", "fm", "fnd", "fot", "fst", "g12", "ggf", "gov",
-                "imb", "ind", "inf", "jor", "jus", "lel", "mat", "med", "mil", "mus", "net", "nom",
-                "not", "ntr", "odo", "org", "ppg", "pro", "psc", "psi", "qsl", "radio", "rec", "slg",
-                "srv", "taxi", "teo", "tmp", "trd", "tur", "tv", "vet", "vlog", "wiki", "zlg")));
-    topMap.put( "bw", new HashSet<String>(Arrays.asList("co", "gov", "org")));
-    topMap.put( "by", new HashSet<String>(Arrays.asList("gov", "mil", "com", "of")));
-    topMap.put( "ca", new HashSet<String>(Arrays.asList("ab", "bc", "mb", "nb", "nf",
-                "nl", "ns", "nt", "nu", "on", "pe", "qc", "sk", "yk", "gc")));
-    topMap.put( "ci", new HashSet<String>(Arrays.asList("org", "or", "com", "co", "edu",
-                "ed", "ac", "net", "go", "asso", "xn--aroport-bya", "int",
-                "presse", "md", "gouv")));
-    topMap.put( "com", new HashSet<String>(Arrays.asList("ad", "ar", "br", "cn", "de", "eu", "gb",
-                "gr", "hu", "jpn", "kr", "no", "qc", "ru", "sa", "se", "uk", "us", "uy", "za")));
-    topMap.put( "cm", new HashSet<String>(Arrays.asList("co", "com", "gov", "net")));
-    topMap.put( "cn", new HashSet<String>(Arrays.asList("ac", "com", "edu", "gov", "net",
-                "org", "mil", "xn--55qx5d", "xn--io0a7i",
-                "ah", "bj", "cq", "fj", "gd", "gs", "gz", "gx",
-                "ha", "hb", "he", "hi", "hl", "hn", "jl", "js", "jx", "ln", "nm", "nx", "qh",
-                "sc", "sd", "sh", "sn", "sx", "tj", "xj", "xz", "yn", "zj", "hk", "mo", "tw")));
-    topMap.put( "co", new HashSet<String>(Arrays.asList("arts", "com", "edu", "firm", "gov", "info",
-                "int", "mil", "net", "nom", "org", "rec", "web")));
-    topMap.put( "cr", new HashSet<String>(Arrays.asList("ac", "co", "ed", "fi", "go", "or", "sa")));
-    topMap.put( "cu", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "gov", "inf")));
-    topMap.put( "do", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "gov", "gob",
-                "web", "art", "sld", "mil")));
-    topMap.put( "dz", new HashSet<String>(Arrays.asList("com", "org", "net", "gov", "edu", "asso",
-                 "pol", "art")));
-    topMap.put( "ec", new HashSet<String>(Arrays.asList("com", "info", "net", "fin", "k12", "med",
-                "pro", "org", "edu", "gov", "gob", "mil")));
-    topMap.put( "ee", new HashSet<String>(Arrays.asList("edu", "gov", "riik", "lib", "med", "com",
-                "pri", "aip", "org", "fie")));
-    topMap.put( "eg", new HashSet<String>(Arrays.asList("com", "edu", "eun", "gov", "mil", "name",
-                "net", "org", "sci")));
-    topMap.put( "es", new HashSet<String>(Arrays.asList("com", "nom", "org", "gob", "edu")));
-    topMap.put( "eu", new HashSet<String>(Arrays.asList("europa")));
-    topMap.put( "fr", new HashSet<String>(Arrays.asList("com", "asso", "nom", "prd", "presse",
-                "tm", "aeroport", "assedic", "avocat", "avoues", "cci", "chambagri",
-                "chirurgiens-dentistes", "experts-comptables", "geometre-expert", "gouv", "greta",
-                "huissier-justice", "medecin", "notaires", "pharmacien", "port", "veterinaire")));
-    topMap.put( "ge", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil", "net", "pvt")));
-    topMap.put( "gg", new HashSet<String>(Arrays.asList("co", "org", "net", "sch", "gov")));
-    topMap.put( "gh", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil")));
-    topMap.put( "gi", new HashSet<String>(Arrays.asList("com", "ltd", "gov", "mod", "edu", "org")));
-    topMap.put( "gn", new HashSet<String>(Arrays.asList("ac", "com", "edu", "gov", "org", "net")));
-    topMap.put( "gp", new HashSet<String>(Arrays.asList("com", "net", "mobi", "edu", "org", "asso")));
-    topMap.put( "gr", new HashSet<String>(Arrays.asList("com", "co", "net", "edu", "org", "gov",
-                "mil", "mod", "sch")));
-    topMap.put( "gy", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "edu", "gov")));
-    topMap.put( "hk", new HashSet<String>(Arrays.asList("com", "edu", "gov", "idv", "net", "org",
-                /* com */ "xn--55qx5d", /* edu */ "xn--wcvs22d", /* gov */"xn--mxtq1m",
-                /* idv */ "xn--gmqw5a", /* net */ "xn--od0alg", /*org*/ "xn--uc0atv")));
-    topMap.put( /* hk */  "xn--j6w193g", new HashSet<String>(Arrays.asList(
-                /* com */ "xn--55qx5d", /* edu */ "xn--wcvs22d", /* gov */"xn--mxtq1m",
-                /* idv */ "xn--gmqw5a", /* net */ "xn--od0alg", /*org*/ "xn--uc0atv")));
-    topMap.put( "hn", new HashSet<String>(Arrays.asList("com", "edu", "org", "net", "mil", "gob")));
-    topMap.put( "hr", new HashSet<String>(Arrays.asList("iz.hr", "from.hr", "name.hr", "com.hr")));
-    topMap.put( "ht", new HashSet<String>(Arrays.asList("com", "shop", "firm", "info", "adult",
-                "net", "pro", "org", "med", "art", "coop", "pol", "asso", "edu", "rel", "gouv", "perso")));
-    topMap.put( "hu", new HashSet<String>(Arrays.asList("co", "info", "org", "priv", "sport", "tm",
-                "2000", "agrar", "bolt", "casino", "city", "erotica", "erotika", "film", "forum",
-                "games", "hotel", "ingatlan", "jogasz", "konyvelo", "lakas", "media", "news", "reklam",
-                "sex", "shop", "suli", "szex", "tozsde", "utazas", "video")));
-    topMap.put( "id", new HashSet<String>(Arrays.asList("ac", "co", "go", "mil", "net", "or", "sch",
-                "web")));
-    topMap.put( "im", new HashSet<String>(Arrays.asList("co.im", "com", "net.im", "gov.im", "org.im",
-                "ac.im")));
-    topMap.put( "in", new HashSet<String>(Arrays.asList("co", "firm", "ernet", "net", "org", "gen", "ind",
-                "nic", "ac", "edu", "res", "gov", "mil")));
-    topMap.put( "iq", new HashSet<String>(Arrays.asList("gov", "edu", "mil", "com", "org", "net" )));
-    topMap.put( "ir", new HashSet<String>(Arrays.asList("ac", "co", "gov", "id", "net", "org", "sch"
-                )));
-    topMap.put( "is", new HashSet<String>(Arrays.asList("net", "com", "edu", "gov", "org", "int")));
-    topMap.put( "it", new HashSet<String>(Arrays.asList("gov", "edu", "agrigento", "ag", "alessandria",
-                "al", "ancona", "an", "aosta", "aoste", "ao", "arezzo", "ar", "ascoli-piceno",
-                "ascolipiceno", "ap", "asti", "at", "avellino", "av", "bari", "ba",
-                "andria-barletta-trani", "andriabarlettatrani", "trani-barletta-andria",
-                "tranibarlettaandria", "barletta-trani-andria", "barlettatraniandria",
-                "andria-trani-barletta", "andriatranibarletta", "trani-andria-barletta",
-                "traniandriabarletta", "bt", "belluno", "bl", "benevento", "bn", "bergamo", "bg",
-                "biella", "bi", "bologna", "bo", "bolzano", "bozen", "balsan", "alto-adige",
-                "altoadige", "suedtirol", "bz", "brescia", "bs", "brindisi", "br", "cagliari",
-                "ca", "caltanissetta", "cl", "campobasso", "cb", "carboniaiglesias", "carbonia-iglesias",
-                "iglesias-carbonia", "iglesiascarbonia", "ci", "caserta", "ce", "catania", "ct",
-                "catanzaro", "cz", "chieti", "ch", "como", "co", "cosenza", "cs", "cremona", "cr",
-                "crotone", "kr", "cuneo", "cn", "dell-ogliastra", "dellogliastra", "ogliastra", "og",
-                "enna", "en", "ferrara", "fe", "fermo", "fm", "firenze", "florence", "fi", "foggia",
-                "fg", "forli-cesena", "forlicesena", "cesena-forli", "cesenaforli", "fc", "frosinone",
-                "fr", "genova", "genoa", "ge", "gorizia", "go", "grosseto", "gr", "imperia", "im",
-                "isernia", "is", "laquila", "aquila", "aq", "la-spezia", "laspezia", "sp", "latina",
-                "lt", "lecce", "le", "lecco", "lc", "livorno", "li", "lodi", "lo", "lucca", "lu",
-                "macerata", "mc", "mantova", "mn", "massa-carrara", "massacarrara", "carrara-massa",
-                "carraramassa", "ms", "matera", "mt", "medio-campidano", "mediocampidano",
-                "campidano-medio", "campidanomedio", "vs", "messina", "me", "milano", "milan",
-                "mi", "modena", "mo", "monza", "monza-brianza", "monzabrianza", "monzaebrianza",
-                "monzaedellabrianza", "monza-e-della-brianza", "mb", "napoli", "naples", "na",
-                "novara", "no", "nuoro", "nu", "oristano", "or", "padova", "padua", "pd", "palermo",
-                "pa", "parma", "pr", "pavia", "pv", "perugia", "pg", "pescara", "pe", "pesaro-urbino",
-                "pesarourbino", "urbino-pesaro", "urbinopesaro", "pu", "piacenza", "pc", "pisa",
-                "pi", "pistoia", "pt", "pordenone", "pn", "potenza", "pz", "prato", "po", "ragusa",
-                "rg", "ravenna", "ra", "reggio-calabria", "reggiocalabria", "rc", "reggio-emilia",
-                "reggioemilia", "re", "rieti", "ri", "rimini", "rn", "roma", "rome", "rm", "rovigo",
-                "ro", "salerno", "sa", "sassari", "ss", "savona", "sv", "siena", "si", "siracusa",
-                "sr", "sondrio", "so", "taranto", "ta", "tempio-olbia", "tempioolbia", "olbia-tempio",
-                "olbiatempio", "ot", "teramo", "te", "terni", "tr", "torino", "turin", "to",
-                "trapani", "tp", "trento", "trentino", "tn", "treviso", "tv", "trieste", "ts",
-                "udine", "ud", "varese", "va", "venezia", "venice", "ve", "verbania", "vb",
-                "vercelli", "vc", "verona", "vr", "vibo-valentia", "vibovalentia", "vv", "vicenza",
-                "vi", "viterbo", "vt")));
-    topMap.put( "je", new HashSet<String>(Arrays.asList("co", "org", "net", "sch", "gov")));
-    topMap.put( "jo", new HashSet<String>(Arrays.asList("com", "org", "net", "edu", "sch",
-                "gov", "mil", "name")));
-    topMap.put( "jp", new HashSet<String>(Arrays.asList("ac", "ad", "co", "ed", "go", "gr", "lg",
-                "ne", "or")));
-    topMap.put( "kg", new HashSet<String>(Arrays.asList("org", "net", "com", "edu", "gov", "mil")));
-    topMap.put( "ki", new HashSet<String>(Arrays.asList("edu", "biz", "net", "org", "gov",
-                 "info", "com")));
-    topMap.put( "km", new HashSet<String>(Arrays.asList("org", "nom", "gov", "prd", "tm", "edu",
-                "mil", "ass", "com", "coop", "asso", "presse", "medecin", "notaires", "pharmaciens",
-                "veterinaire", "gouv")));
-    topMap.put( "kn", new HashSet<String>(Arrays.asList("net", "org", "edu", "gov")));
-    topMap.put( "kp", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "rep", "tra")));
-    topMap.put( "kr", new HashSet<String>(Arrays.asList("ac", "co", "es", "go", "hs", "kg", "mil",
-                "ms", "ne", "or", "pe", "re", "sc", "busan", "chungbuk", "chungnam", "daegu",
-                "daejeon", "gangwon", "gwangju", "gyeongbuk", "gyeonggi", "gyeongnam", "incheon",
-                "jeju", "jeonbuk", "jeonnam", "seoul", "ulsan")));
-    topMap.put( "kz", new HashSet<String>(Arrays.asList("org", "edu", "net", "gov", "mil", "com")));
-    topMap.put( "la", new HashSet<String>(Arrays.asList("int", "net", "info", "edu", "gov", "per",
-                "com", "org", "c")));
-    topMap.put( "lc", new HashSet<String>(Arrays.asList("com", "net", "co", "org", "edu", "gov",
-                "l.lc", "p.lc")));
-    topMap.put( "lk", new HashSet<String>(Arrays.asList("gov", "sch", "net", "int", "com", "org",
-                "edu", "ngo", "soc", "web", "ltd", "assn", "grp", "hotel")));
-    topMap.put( "ls", new HashSet<String>(Arrays.asList("co", "gov", "ac", "org")));
-    topMap.put( "lv", new HashSet<String>(Arrays.asList("com", "edu", "gov", "org", "mil",
-                "id", "net", "asn", "conf")));
-    topMap.put( "ly", new HashSet<String>(Arrays.asList("com", "net", "gov", "plc", "edu", "sch",
-                "med", "org", "id")));
-    topMap.put( "ma", new HashSet<String>(Arrays.asList("co", "net", "gov", "org", "ac", "press")));
-    topMap.put( "me", new HashSet<String>(Arrays.asList("co", "net", "org", "edu", "ac", "gov",
-                "its", "priv")));
-    topMap.put( "mg", new HashSet<String>(Arrays.asList("org", "nom", "gov", "prd", "tm",
-                "edu", "mil", "com")));
-    topMap.put( "mk", new HashSet<String>(Arrays.asList("com", "org", "net", "edu", "gov", "inf",
-                "name", "pro")));
-    topMap.put( "ml", new HashSet<String>(Arrays.asList("com", "edu", "gouv", "gov", "net",
-                "org", "presse")));
-    topMap.put( "mn", new HashSet<String>(Arrays.asList("gov", "edu", "org")));
-    topMap.put( "mp", new HashSet<String>(Arrays.asList("gov", "co", "org")));
-    topMap.put( "mu", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "ac",
-                "co", "or")));
-    topMap.put( "museum", new HashSet<String>(Arrays.asList("academy", "agriculture", "air",
-                "airguard", "alabama", "alaska", "amber", "ambulance", "american", "americana",
-                "americanantiques", "americanart", "amsterdam", "and", "annefrank", "anthro",
-                "anthropology", "antiques", "aquarium", "arboretum", "archaeological", "archaeology",
-                "architecture", "art", "artanddesign", "artcenter", "artdeco", "arteducation",
-                "artgallery", "arts", "artsandcrafts", "asmatart", "assassination", "assisi",
-                "association", "astronomy", "atlanta", "austin", "australia", "automotive", "aviation",
-                "axis", "badajoz", "baghdad", "bahn", "bale", "baltimore", "barcelona", "baseball",
-                "basel", "baths", "bauern", "beauxarts", "beeldengeluid", "bellevue", "bergbau",
-                "berkeley", "berlin", "bern", "bible", "bilbao", "bill", "birdart", "birthplace",
-                "bonn", "boston", "botanical", "botanicalgarden", "botanicgarden", "botany",
-                "brandywinevalley", "brasil", "bristol", "british", "britishcolumbia", "broadcast",
-                "brunel", "brussel", "brussels", "bruxelles", "building", "burghof", "bus", "bushey",
-                "cadaques", "california", "cambridge", "can", "canada", "capebreton", "carrier",
-                "cartoonart", "casadelamoneda", "castle", "castres", "celtic", "center", "chattanooga",
-                "cheltenham", "chesapeakebay", "chicago", "children", "childrens", "childrensgarden",
-                "chiropractic", "chocolate", "christiansburg", "cincinnati", "cinema", "circus",
-                "civilisation", "civilization", "civilwar", "clinton", "clock", "coal", "coastaldefence",
-                "cody", "coldwar", "collection", "colonialwilliamsburg", "coloradoplateau", "columbia",
-                "columbus", "communication", "communications", "community", "computer",
-                "computerhistory", "xn--comunicaes-v6a2o", "contemporary", "contemporaryart",
-                "convent", "copenhagen", "corporation", "xn--correios-e-telecomunicaes-ghc29a",
-                "corvette", "costume", "countryestate", "county", "crafts", "cranbrook", "creation",
-                "cultural", "culturalcenter", "culture", "cyber", "cymru", "dali", "dallas", "database",
-                "ddr", "decorativearts", "delaware", "delmenhorst", "denmark", "depot", "design",
-                "detroit", "dinosaur", "discovery", "dolls", "donostia", "durham", "eastafrica",
-                "eastcoast", "education", "educational", "egyptian", "eisenbahn", "elburg",
-                "elvendrell", "embroidery", "encyclopedic", "england", "entomology", "environment",
-                "environmentalconservation", "epilepsy", "essex", "estate", "ethnology", "exeter",
-                "exhibition", "family", "farm", "farmequipment", "farmers", "farmstead", "field",
-                "figueres", "filatelia", "film", "fineart", "finearts", "finland", "flanders", "florida",
-                "force", "fortmissoula", "fortworth", "foundation", "francaise", "frankfurt",
-                "franziskaner", "freemasonry", "freiburg", "fribourg", "frog", "fundacio", "furniture",
-                "gallery", "garden", "gateway", "geelvinck", "gemological", "geology", "georgia",
-                "giessen", "glas", "glass", "gorge", "grandrapids", "graz", "guernsey", "halloffame",
-                "hamburg", "handson", "harvestcelebration", "hawaii", "health", "heimatunduhren",
-                "hellas", "helsinki", "hembygdsforbund", "heritage", "histoire", "historical",
-                "historicalsociety", "historichouses", "historisch", "historisches", "history",
-                "historyofscience", "horology", "house", "humanities", "illustration", "imageandsound",
-                "indian", "indiana", "indianapolis", "indianmarket", "intelligence", "interactive",
-                "iraq", "iron", "isleofman", "jamison", "jefferson", "jerusalem", "jewelry",
-                "jewish", "jewishart", "jfk", "journalism", "judaica", "judygarland", "juedisches",
-                "juif", "karate", "karikatur", "kids", "koebenhavn", "koeln", "kunst", "kunstsammlung",
-                "kunstunddesign", "labor", "labour", "lajolla", "lancashire", "landes", "lans",
-                "xn--lns-qla", "larsson", "lewismiller", "lincoln", "linz", "living", "livinghistory",
-                "localhistory", "london", "losangeles", "louvre", "loyalist", "lucerne", "luxembourg",
-                "luzern", "mad", "madrid", "mallorca", "manchester", "mansion", "mansions", "manx",
-                "marburg", "maritime", "maritimo", "maryland", "marylhurst", "media", "medical",
-                "medizinhistorisches", "meeres", "memorial", "mesaverde", "michigan", "midatlantic",
-                "military", "mill", "miners", "mining", "minnesota", "missile", "missoula", "modern",
-                "moma", "money", "monmouth", "monticello", "montreal", "moscow", "motorcycle", "muenchen",
-                "muenster", "mulhouse", "muncie", "museet", "museumcenter", "museumvereniging", "music",
-                "national", "nationalfirearms", "nationalheritage", "nativeamerican", "naturalhistory",
-                "naturalhistorymuseum", "naturalsciences", "nature", "naturhistorisches",
-                "natuurwetenschappen", "naumburg", "naval", "nebraska", "neues", "newhampshire",
-                "newjersey", "newmexico", "newport", "newspaper", "newyork", "niepce", "norfolk",
-                "north", "nrw", "nuernberg", "nuremberg", "nyc", "nyny", "oceanographic",
-                "oceanographique", "omaha", "online", "ontario", "openair", "oregon", "oregontrail",
-                "otago", "oxford", "pacific", "paderborn", "palace", "paleo", "palmsprings", "panama",
-                "paris", "pasadena", "pharmacy", "philadelphia", "philadelphiaarea", "philately",
-                "phoenix", "photography", "pilots", "pittsburgh", "planetarium", "plantation",
-                "plants", "plaza", "portal", "portland", "portlligat", "posts-and-telecommunications",
-                "preservation", "presidio", "press", "project", "public", "pubol", "quebec",
-                "railroad", "railway", "research", "resistance", "riodejaneiro", "rochester", "rockart",
-                "roma", "russia", "saintlouis", "salem", "salvadordali", "salzburg", "sandiego",
-                "sanfrancisco", "santabarbara", "santacruz", "santafe", "saskatchewan", "satx",
-                "savannahga", "schlesisches", "schoenbrunn", "schokoladen", "school", "schweiz",
-                "science", "scienceandhistory", "scienceandindustry", "sciencecenter", "sciencecenters",
-                "science-fiction", "sciencehistory", "sciences", "sciencesnaturelles", "scotland",
-                "seaport", "settlement", "settlers", "shell", "sherbrooke", "sibenik", "silk", "ski",
-                "skole", "society", "sologne", "soundandvision", "southcarolina", "southwest", "space",
-                "spy", "square", "stadt", "stalbans", "starnberg", "state", "stateofdelaware",
-                "station", "steam", "steiermark", "stjohn", "stockholm", "stpetersburg", "stuttgart",
-                "suisse", "surgeonshall", "surrey", "svizzera", "sweden", "sydney", "tank", "tcm",
-                "technology", "telekommunikation", "television", "texas", "textile", "theater",
-                "time", "timekeeping", "topology", "torino", "touch", "town", "transport", "tree",
-                "trolley", "trust", "trustee", "uhren", "ulm", "undersea", "university", "usa",
-                "usantiques", "usarts", "uscountryestate", "usculture", "usdecorativearts", "usgarden",
-                "ushistory", "ushuaia", "uslivinghistory", "utah", "uvic", "valley", "vantaa",
-                "versailles", "viking", "village", "virginia", "virtual", "virtuel", "vlaanderen",
-                "volkenkunde", "wales", "wallonie", "war", "washingtondc", "watchandclock",
-                "watch-and-clock", "western", "westfalen", "whaling", "wildlife", "williamsburg",
-                "windmill", "workshop", "york", "yorkshire", "yosemite", "youth", "zoological",
-                "zoology", "xn--9dbhblg6di", "xn--h1aegh")));
-    topMap.put( "mv", new HashSet<String>(Arrays.asList("aero", "biz", "com", "coop", "edu", "gov",
-                "info", "int", "mil", "museum", "name", "net", "org", "pro")));
-    topMap.put( "mw", new HashSet<String>(Arrays.asList("ac", "biz", "co", "com", "coop", "edu",
-                "gov", "int", "museum", "net", "org")));
-    topMap.put( "mx", new HashSet<String>(Arrays.asList("com", "org", "gob", "edu", "net")));
-    topMap.put( "my", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu",
-                 "mil", "name", "sch")));
-    topMap.put( "na", new HashSet<String>(Arrays.asList("co", "com", "org", "edu", "edunet", "net",
-                "alt", "biz", "info")));
-    topMap.put( "nc", new HashSet<String>(Arrays.asList("asso", "nom")));
-    topMap.put( "net", new HashSet<String>(Arrays.asList("gb", "se", "uk", "za")));
-    topMap.put( "ng", new HashSet<String>(Arrays.asList("name", "sch", "mil", "mobi", "com",
-                "edu", "gov", "net", "org")));
-    topMap.put( "nf", new HashSet<String>(Arrays.asList("com", "net", "per", "rec", "web",
-                "arts", "firm", "info", "other", "store")));
-    topMap.put( "no", new HashSet<String>(Arrays.asList("fhs", "vgs", "fylkesbibl", "folkebibl",
-                "museum", "idrett", "priv", "mil", "stat", "dep", "kommune", "herad", "aa",
-                "ah", "bu", "fm", "hl", "hm", "jan-mayen", "mr", "nl", "nt", "of", "ol", "oslo",
-                "rl", "sf", "st", "svalbard", "tm", "tr", "va", "vf", "akrehamn",
-                "xn--krehamn-dxa", "algard", "xn--lgrd-poac", "arna", "brumunddal",
-                "bryne", "bronnoysund", "xn--brnnysund-m8ac", "drobak",
-                "xn--drbak-wua", "egersund", "fetsund", "floro", "xn--flor-jra",
-                "fredrikstad", "hokksund", "honefoss", "xn--hnefoss-q1a",
-                "jessheim", "jorpeland", "xn--jrpeland-54a", "kirkenes", "kopervik",
-                "krokstadelva", "langevag", "xn--langevg-jxa", "leirvik", "mjondalen",
-                "xn--mjndalen-64a", "mo-i-rana", "mosjoen", "xn--mosjen-eya",
-                "nesoddtangen", "orkanger", "osoyro", "xn--osyro-wua",
-                "raholt", "xn--rholt-mra", "sandnessjoen", "xn--sandnessjen-ogb",
-                "skedsmokorset", "slattum", "spjelkavik", "stathelle", "stavern", "stjordalshalsen",
-                "xn--stjrdalshalsen-sqb", "tananger", "tranby", "vossevangen", "tranby",
-                "vossevangen", "afjord", "xn--fjord-lra", "agdenes", "al",
-                "xn--l-1fa", "alesund", "xn--lesund-hua",
-                "alstahaug", "alta", "xn--lt-liac", "alaheadju",
-                "xn--laheadju-7ya", "alvdal", "amli", "xn--mli-tla",
-                "amot", "xn--mot-tla", "andebu", "andoy", "xn--andy-ira",
-                "andasuolo", "ardal", "xn--rdal-poa", "aremark", "arendal",
-                "xn--s-1fa", "aseral", "xn--seral-lra",
-                "asker", "askim", "askvoll", "askoy", "xn--asky-ira",
-                "asnes", "xn--snes-poa", "audnedaln", "aukra", "aure", "aurland",
-                "aurskog-holand", "xn--aurskog-hland-jnb",
-                "austevoll", "austrheim", "averoy", "xn--avery-yua",
-                "balestrand", "ballangen", "balat", "xn--blt-elab",
-                "balsfjord", "bahccavuotna", "xn--bhccavuotna-k7a",
-                "bamble", "bardu", "beardu", "beiarn", "bajddar", "xn--bjddar-pta",
-                "baidar", "xn--bidr-5nac", "berg", "bergen", "berlevag", "xn--berlevg-jxa",
-                "bearalvahki", "xn--bearalvhki-y4a", "bindal", "birkenes", "bjarkoy",
-                "xn--bjarky-fya", "bjerkreim", "bjugn", "bodo", "xn--bod-2na",
-                "badaddja", "xn--bdddj-mrabd", "budejju", "bokn",
-                "bremanger", "bronnoy", "xn--brnny-wuac", "bygland",
-                "bykle", "barum", "xn--brum-voa", "bievat", "xn--bievt-0qa",
-                "bomlo", "xn--bmlo-gra", "batsfjord", "xn--btsfjord-9za", "bahcavuotna",
-                "xn--bhcavuotna-s4a", "dovre", "drammen", "drangedal", "dyroy",
-                "xn--dyry-ira", "donna", "xn--dnna-gra",
-                "eid", "eidfjord", "eidsberg", "eidskog", "eidsvoll", "eigersund", "elverum",
-                "enebakk", "engerdal", "etne", "etnedal", "evenes", "evenassi",
-                "xn--eveni-0qa01ga", "evje-og-hornnes", "farsund", "fauske",
-                "fuossko", "fuoisku", "fedje", "fet", "finnoy", "xn--finny-yua",
-                "fitjar", "fjaler", "fjell", "flakstad", "flatanger", "flekkefjord", "flesberg",
-                "flora", "fla", "xn--fl-zia", "folldal", "forsand", "fosnes", "frei",
-                "frogn", "froland", "frosta", "frana", "xn--frna-woa",
-                "froya", "xn--frya-hra", "fusa", "fyresdal", "forde",
-                "xn--frde-gra", "gamvik", "gangaviika", "xn--ggaviika-8ya47h",
-                "gaular", "gausdal", "gildeskal", "xn--gildeskl-g0a",
-                "giske", "gjemnes", "gjerdrum", "gjerstad", "gjesdal", "gjovik",
-                "xn--gjvik-wua", "gloppen", "gol", "gran", "grane", "granvin",
-                "gratangen", "grimstad", "grong", "kraanghke", "xn--kranghke-b0a",
-                "grue", "gulen", "hadsel", "halden", "halsa", "hamar", "hamaroy", "habmer",
-                "xn--hbmer-xqa",  "hapmir", "xn--hpmir-xqa",
-                "hammerfest", "hammarfeasta", "xn--hmmrfeasta-s4ac",
-                "haram", "hareid", "harstad", "hasvik", "aknoluokta", "xn--koluokta-7ya57h",
-                "hattfjelldal", "aarborte", "haugesund", "hemne", "hemnes", "hemsedal",
-                "hitra", "hjartdal", "hjelmeland",
-                "hobol", "xn--hobl-ira", "hof", "hol", "hole", "holmestrand", "holtalen",
-                "xn--holtlen-hxa", "hornindal", "horten", "hurdal", "hurum", "hvaler",
-                "hyllestad", "hagebostad", "xn--hgebostad-g3a",  "hoyanger",
-                "xn--hyanger-q1a", "hoylandet", "xn--hylandet-54a",
-                "ha", "xn--h-2fa", "ibestad", "inderoy", "xn--indery-fya",
-                "iveland", "jevnaker", "jondal", "jolster", "xn--jlster-bya",
-                "karasjok", "karasjohka", "xn--krjohka-hwab49j",
-                "karlsoy", "galsa", "xn--gls-elac", "karmoy",
-                "xn--karmy-yua", "kautokeino", "guovdageaidnu", "klepp", "klabu",
-                "xn--klbu-woa", "kongsberg", "kongsvinger", "kragero", "xn--krager-gya",
-                "kristiansand", "kristiansund", "krodsherad", "xn--krdsherad-m8a",
-                "kvalsund", "rahkkeravju", "xn--rhkkervju-01af",
-                "kvam", "kvinesdal", "kvinnherad", "kviteseid", "kvitsoy", "xn--kvitsy-fya",
-                "kvafjord", "xn--kvfjord-nxa", "giehtavuoatna", "kvanangen",
-                "xn--kvnangen-k0a", "navuotna", "xn--nvuotna-hwa",
-                "kafjord", "xn--kfjord-iua", "gaivuotna", "xn--givuotna-8ya",
-                "larvik", "lavangen", "lavagis", "loabat", "xn--loabt-0qa",
-                "lebesby", "davvesiida", "leikanger", "leirfjord", "leka", "leksvik", "lenvik",
-                "leangaviika", "xn--leagaviika-52b", "lesja", "levanger", "lier", "lierne",
-                "lillehammer", "lillesand", "lindesnes", "lindas", "xn--linds-pra",
-                "lom", "loppa", "lahppi", "xn--lhppi-xqa", "lund", "lunner", "luroy",
-                "xn--lury-ira", "luster", "lyngdal", "lyngen", "ivgu", "lardal", "lerdal",
-                "xn--lrdal-sra", "lodingen", "xn--ldingen-q1a", "lorenskog",
-                "xn--lrenskog-54a", "loten", "xn--lten-gra",  "malvik",
-                "masoy", "xn--msy-ula0h", "muosat", "xn--muost-0qa",
-                "mandal", "marker", "marnardal", "masfjorden", "meland", "meldal", "melhus",
-                "meloy", "xn--mely-ira", "meraker", "xn--merker-kua", "moareke",
-                "xn--moreke-jua", "midsund", "midtre-gauldal", "modalen", "modum",
-                "molde", "moskenes", "moss", "mosvik", "malselv", "xn--mlselv-iua",
-                "malatvuopmi", "xn--mlatvuopmi-s4a", "namdalseid", "aejrie", "namsos",
-                "namsskogan", "naamesjevuemie", "xn--nmesjevuemie-tcba",
-                "laakesvuemie", "nannestad", "narvik", "narviika", "naustdal", "nedre-eiker",
-                "nesna", "nesodden", "nesseby", "unjarga", "xn--unjrga-rta", "nesset",
-                "nissedal", "nittedal", "nord-aurdal", "nord-fron", "nord-odal", "norddal",
-                "nordkapp", "davvenjarga", "xn--davvenjrga-y4a", "nordre-land",
-                "nordreisa", "raisa", "xn--risa-5na", "nore-og-uvdal", "notodden", "naroy",
-                "xn--nry-yla5g", "notteroy", "xn--nttery-byae",
-                "odda", "oksnes", "xn--ksnes-uua", "oppdal", "oppegard",
-                "xn--oppegrd-ixa", "orkdal", "orland", "xn--rland-uua",
-                "orskog", "xn--rskog-uua", "orsta", "xn--rsta-fra",
-                "os.hedmark", "os.hordaland", "osen", "osteroy", "xn--ostery-fya",
-                "ostre-toten", "xn--stre-toten-zcb", "overhalla", "ovre-eiker",
-                "xn--vre-eiker-k8a", "oyer", "xn--yer-zna",
-                "oygarden", "xn--ygarden-p1a",  "oystre-slidre", "xn--ystre-slidre-ujb",
-                "porsanger", "porsangu", "xn--porsgu-sta26f", "porsgrunn",
-                "radoy", "xn--rady-ira", "rakkestad", "rana", "ruovat", "randaberg",
-                "rauma", "rendalen", "rennebu", "rennesoy", "xn--rennesy-v1a",
-                "rindal", "ringebu", "ringerike", "ringsaker", "rissa", "risor",
-                "xn--risr-ira", "roan", "rollag", "rygge", "ralingen", "xn--rlingen-mxa",
-                "rodoy", "xn--rdy-0nab", "romskog", "xn--rmskog-bya",
-                "roros", "xn--rros-gra", "rost", "xn--rst-0na",
-                "royken", "xn--ryken-vua", "royrvik", "xn--ryrvik-bya",
-                "rade", "xn--rde-ula", "salangen", "siellak", "saltdal", "salat",
-                "xn--slt-elab", "xn--slat-5na", "samnanger",
-                "sandefjord", "sandnes", "sandoy", "xn--sandy-yua", "sarpsborg",
-                "sauda", "sauherad", "sel", "selbu", "selje", "seljord", "sigdal", "siljan",
-                "sirdal", "skaun", "skedsmo", "ski", "skien", "skiptvet", "skjervoy",
-                "xn--skjervy-v1a", "skierva", "xn--skierv-uta",
-                "skjak", "xn--skjk-soa",  "skodje", "skanland", "xn--sknland-fxa",
-                "skanit", "xn--sknit-yqa",  "smola", "xn--smla-hra",
-                "snillfjord", "snasa", "xn--snsa-roa",  "snoasa", "snaase",
-                "xn--snase-nra", "sogndal", "sokndal", "sola", "solund", "songdalen",
-                "sortland", "spydeberg", "stange", "stavanger", "steigen", "steinkjer",
-                "stjordal", "xn--stjrdal-s1a", "stokke", "stor-elvdal", "stord", "stordal",
-                "storfjord", "omasvuotna", "strand", "stranda", "stryn", "sula", "suldal",
-                "sund", "sunndal", "surnadal", "sveio", "svelvik", "sykkylven", "sogne",
-                "xn--sgne-gra", "somna", "xn--smna-gra", "sondre-land",
-                "xn--sndre-land-0cb", "sor-aurdal", "xn--sr-aurdal-l8a",
-                "sor-fron", "xn--sr-fron-q1a", "sor-odal", "xn--sr-odal-q1a",
-                "sor-varanger", "xn--sr-varanger-ggb",  "matta-varjjat",
-                "xn--mtta-vrjjat-k7af", "sorfold", "xn--srfold-bya",
-                "sorreisa", "xn--srreisa-q1a", "sorum", "xn--srum-gra",
-                "tana", "deatnu", "time", "tingvoll", "tinn", "tjeldsund", "dielddanuorri",
-                "tjome", "xn--tjme-hra", "tokke", "tolga", "torsken", "tranoy",
-                "xn--trany-yua",  "tromso", "xn--troms-zua",  "tromsa", "romsa",
-                "trondheim", "troandin", "trysil", "trana", "xn--trna-woa",
-                "trogstad", "xn--trgstad-r1a",  "tvedestrand", "tydal", "tynset",
-                "tysfjord", "divtasvuodna", "divttasvuotna", "tysnes", "tysvar",
-                "xn--tysvr-vra",  "tonsberg", "xn--tnsberg-q1a",
-                "ullensaker", "ullensvang", "ulvik", "utsira", "vadso", "xn--vads-jra",
-                "cahcesuolo", "xn--hcesuolo-7ya35b",  "vaksdal", "valle", "vang",
-                "vanylven", "vardo", "xn--vard-jra",  "varggat", "xn--vrggt-xqad",
-                "vefsn", "vaapste", "vega", "vegarshei", "xn--vegrshei-c0a", "vennesla",
-                "verdal", "verran", "vestby", "vestnes", "vestre-slidre", "vestre-toten",
-                "vestvagoy", "xn--vestvgy-ixa6o", "vevelstad", "vik", "vikna",
-                "vindafjord", "volda", "voss", "varoy", "xn--vry-yla5g",
-                "vagan", "xn--vgan-qoa", "voagat", "vagsoy", "xn--vgsy-qoa0j",
-                "vaga", "xn--vg-yiab")));
-
-    topMap.put( "nr", new HashSet<String>(Arrays.asList("biz", "info", "gov", "edu", "org",
-                 "net", "com", "co")));
-    topMap.put( "pa", new HashSet<String>(Arrays.asList("ac", "gob", "com", "org",
-                "sld", "edu", "net", "ing", "abo", "med", "nom")));
-    topMap.put( "pe", new HashSet<String>(Arrays.asList("edu", "gob", "nom", "mil", "org", "com",
-                "net", "sld")));
-    topMap.put( "pf", new HashSet<String>(Arrays.asList( "com")));
-    topMap.put( "ph", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "ngo", "mil")));
-    topMap.put( "pk", new HashSet<String>(Arrays.asList("com", "net", "edu", "org", "fam", "biz",
-                "web", "gov", "gob", "gok", "gon", "gop", "gos", "gog", "gkp", "info")));
-    topMap.put( "pl", new HashSet<String>(Arrays.asList("aid", "agro", "atm", "auto", "biz", "com",
-                "edu", "gmina", "gsm", "info", "mail", "miasta", "media", "mil", "net", "nieruchomosci",
-                "nom", "org", "pc", "powiat", "priv", "realestate", "rel", "sex", "shop", "sklep",
-                "sos", "szkola", "targi", "tm", "tourism", "travel", "turystyka", "art",
-                "gov", "ngo", "augustow", "babia-gora", "bedzin", "beskidy",
-                "bialowieza", "bialystok", "bielawa", "bieszczady", "boleslawiec", "bydgoszcz",
-                "bytom", "cieszyn", "czeladz", "czest", "dlugoleka", "elblag", "elk", "glogow",
-                "gniezno", "gorlice", "grajewo", "ilawa", "jaworzno", "jelenia-gora", "jgora",
-                "kalisz", "kazimierz-dolny", "karpacz", "kartuzy", "kaszuby", "katowice", "kepno",
-                "ketrzyn", "klodzko", "kobierzyce", "kolobrzeg", "konin", "konskowola", "kutno",
-                "lapy", "lebork", "legnica", "lezajsk", "limanowa", "lomza", "lowicz", "lubin",
-                "lukow", "malbork", "malopolska", "mazowsze", "mazury", "mielec", "mielno", "mragowo",
-                "naklo", "nowaruda", "nysa", "olawa", "olecko", "olkusz", "olsztyn", "opoczno",
-                "opole", "ostroda", "ostroleka", "ostrowiec", "ostrowwlkp", "pila", "pisz", "podhale",
-                "podlasie", "polkowice", "pomorze", "pomorskie", "prochowice", "pruszkow", "przeworsk",
-                "pulawy", "radom", "rawa-maz", "rybnik", "rzeszow", "sanok", "sejny", "siedlce",
-                "slask", "slupsk", "sosnowiec", "stalowa-wola", "skoczow", "starachowice", "stargard",
-                "suwalki", "swidnica", "swiebodzin", "swinoujscie", "szczecin", "szczytno", "tarnobrzeg",
-                "tgory", "turek", "tychy", "ustka", "walbrzych", "warmia", "warszawa", "waw",
-                "wegrow", "wielun", "wlocl", "wloclawek", "wodzislaw", "wolomin", "wroclaw",
-                "zachpomor", "zagan", "zarow", "zgora", "zgorzelec", "gda", "gdansk",
-                "krakow", "poznan", "wroc", "co",
-                "lodz", "lublin", "torun")));
-    topMap.put( "pn", new HashSet<String>(Arrays.asList("gov", "co", "org", "edu", "net")));
-    topMap.put( "pr", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "isla",
-                "pro", "biz", "info", "name", "est", "prof", "ac", "gobierno")));
-    topMap.put( "pro", new HashSet<String>(Arrays.asList("aca", "bar", "cpa", "jur", "law",
-                 "med", "eng")));
-    topMap.put( "ps", new HashSet<String>(Arrays.asList("edu", "gov", "sec", "plo", "com", "org", "net")));
-    topMap.put( "pt", new HashSet<String>(Arrays.asList("net", "gov", "org", "edu", "int", "publ",
-                 "com", "nome")));
-    topMap.put( "pw", new HashSet<String>(Arrays.asList("co", "ne", "or", "ed", "go", "belau")));
-    topMap.put( "qa", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "mil")));
-    topMap.put( "re", new HashSet<String>(Arrays.asList("com", "asso", "nom")));
-    topMap.put( "ro", new HashSet<String>(Arrays.asList("com", "org", "tm", "nt", "nom", "info",
-                "rec", "arts", "firm", "store", "www")));
-    topMap.put( "rs", new HashSet<String>(Arrays.asList("co", "org", "edu", "ac", "gov", "in")));
-    topMap.put( "ru", new HashSet<String>(Arrays.asList("ac", "com", "edu", "int", "net", "org",
-                "pp", "adygeya", "altai", "amur", "arkhangelsk", "astrakhan", "bashkiria",
-                "belgorod", "bir", "bryansk", "buryatia", "cap", "cbg", "chel", "chelyabinsk", "chita",
-                "chukotka", "dagestan", "e-burg", "grozny", "irkutsk",
-                "ivanovo", "izhevsk", "jar", "joshkar-ola", "kalmykia", "kaluga", "kamchatka",
-                "karelia", "kazan", "kchr", "kemerovo", "khabarovsk", "khakassia", "khv", "kirov",
-                "koenig", "komi", "kostroma", "krasnoyarsk", "kuban", "kurgan", "kursk", "lipetsk",
-                "magadan", "mari", "mari-el", "marine", "mordovia", "mosreg", "msk", "murmansk",
-                "nalchik", "nnov", "nov", "novosibirsk", "nsk", "omsk", "orenburg", "oryol",
-                "palana", "penza", "perm", "pskov", "ptz", "rnd", "ryazan", "sakhalin", "samara",
-                "saratov", "simbirsk", "smolensk", "spb", "stavropol", "stv", "surgut", "tambov",
-                "tatarstan", "tom", "tomsk", "tsaritsyn", "tsk", "tula", "tuva", "tver", "tyumen",
-                "udm", "udmurtia", "ulan-ude", "vladikavkaz", "vladimir", "vladivostok", "volgograd",
-                "vologda", "voronezh", "vrn", "vyatka", "yakutia", "yamal", "yaroslavl",
-                "yekaterinburg", "yuzhno-sakhalinsk", "amursk", "baikal", "cmw", "fareast",
-                "jamal", "kms", "k-uralsk", "kustanai", "kuzbass", "magnitka", "mytis",
-                "nakhodka", "nkz", "norilsk", "oskol", "pyatigorsk", "rubtsovsk", "snz", "syzran",
-                "vdonsk", "zgrad", "gov", "mil", "test")));
-    topMap.put( "rw", new HashSet<String>(Arrays.asList("gov", "net", "edu", "ac", "com", "co",
-                "int", "mil", "gouv")));
-    topMap.put( "sa", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "med", "pub",
-                "edu", "sch")));
-    topMap.put( "sd", new HashSet<String>(Arrays.asList("com", "net", "org", "edu", "med", "gov",
-                "info", "tv")));
-    topMap.put( "se", new HashSet<String>(Arrays.asList("a", "ac", "b", "bd", "brand", "c", "d",
-                "e", "f", "fh", "fhsk", "fhv", "g", "h", "i", "k", "komforb", "kommunalforbund",
-                "komvux", "l", "lanarb", "lanbib", "m", "n", "naturbruksgymn", "o", "org", "p", "parti",
-                "pp", "press", "r", "s", "sshn", "t", "tm", "u", "w", "x", "y", "z")));
-    topMap.put( "sg", new HashSet<String>(Arrays.asList("com", "net", "org", "gov", "edu", "per")));
-    topMap.put( "sh", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "gov", "edu", "nom")));
-    topMap.put( "sk", new HashSet<String>(Arrays.asList("gov", "edu")));
-    topMap.put( "sn", new HashSet<String>(Arrays.asList("art", "com", "edu", "gouv", "org", "perso",
-                "univ")));
-    topMap.put( "so", new HashSet<String>(Arrays.asList("com", "net", "org")));
-    topMap.put( "sr", new HashSet<String>(Arrays.asList("co", "com", "consulado", "edu", "embaixada",
-                "gov", "mil", "net", "org", "principe", "saotome", "store")));
-    topMap.put( "sy", new HashSet<String>(Arrays.asList("edu", "gov", "net", "mil", "com", "org", "news")));
-    topMap.put( "sz", new HashSet<String>(Arrays.asList("co", "ac", "org")));
-    topMap.put( "th", new HashSet<String>(Arrays.asList("ac", "co", "go", "in", "mi", "net", "or")));
-    topMap.put( "tj", new HashSet<String>(Arrays.asList("ac", "biz", "co", "com", "edu", "go", "gov",
-                "int", "mil", "name", "net", "nic", "org", "test", "web")));
-    topMap.put( "tn", new HashSet<String>(Arrays.asList("com", "ens", "fin", "gov", "ind", "intl",
-                "nat", "net", "org", "info", "perso", "tourism", "edunet", "rnrt", "rns", "rnu",
-                "mincom", "agrinet", "defense", "turen")));
-    topMap.put( "to", new HashSet<String>(Arrays.asList("gov")));
-    topMap.put( "tt", new HashSet<String>(Arrays.asList("co", "com", "org", "net", "biz", "info",
-                "pro", "int", "coop", "jobs", "mobi", "travel", "museum", "aero", "name", "gov",
-                "edu", "cat", "tel", "mil")));
-    topMap.put( "tw", new HashSet<String>(Arrays.asList("edu", "gov", "mil", "com", "net", "org",
-                "idv", "game", "ebiz", "club", "xn--zf0ao64a", "xn--uc0atv", "xn--czrw28b")));
-    topMap.put( "ua", new HashSet<String>(Arrays.asList("com", "edu", "gov", "in", "net", "org",
-                "cherkassy", "chernigov", "chernovtsy", "ck", "cn", "crimea", "cv", "dn",
-                "dnepropetrovsk", "donetsk", "dp", "if", "ivano-frankivsk", "kh", "kharkov",
-                "kherson", "kiev", "kirovograd", "km", "kr", "ks", "lg",
-                "lugansk", "lutsk", "lviv", "mk", "nikolaev", "od", "odessa", "pl", "poltava",
-                "rovno", "rv", "sebastopol", "sumy", "te", "ternopil", "uzhgorod", "vinnica", "vn",
-                "zaporizhzhe", "zp", "zhitomir", "zt", "cr", "lt", "lv", "sb", "sm", "tr",
-                "co", "biz", "in", "ne", "pp", "uz", "dominic")));
-    topMap.put( "ug", new HashSet<String>(Arrays.asList("co", "ac", "sc", "go", "ne", "or", "org", "com")));
-    topMap.put( "us", new HashSet<String>(Arrays.asList("dni", "fed", "isa", "kids", "nsn", "kyschools")));
-    topMap.put( "uz", new HashSet<String>(Arrays.asList("co", "com", "org", "gov", "ac", "edu", "int", "pp", "net")));
-    topMap.put( "vc", new HashSet<String>(Arrays.asList("com", "net", "org", "gov")));
-    topMap.put( "vi", new HashSet<String>(Arrays.asList("co", "com", "k12", "net", "org")));
-    topMap.put( "vn", new HashSet<String>(Arrays.asList( "com", "net", "org", "edu", "gov", "int",
-                "ac", "biz", "info", "name", "pro", "health")));
-    topMap.put( "vu", new HashSet<String>(Arrays.asList("co", "com", "net", "org", "edu", "gov", "de")));
-    topMap.put("org", new HashSet<String>(Arrays.asList("ae", "za")));
-    topMap.put("pro", new HashSet<String>(Arrays.asList("aca", "bar", "cpa", "jur", "law", "med", "eng")));
-
-    top3Map.put("au", new HashSet<String>(Arrays.asList("act.edu.au", "eq.edu.au",
-                "nsw.edu.au", "nt.edu.au", "qld.edu.au", "sa.edu.au", "tas.edu.au", "vic.edu.au",
-                 "wa.edu.au", "act.gov.au", "nsw.gov.au", "nt.gov.au", "qld.gov.au", "sa.gov.au",
-                 "tas.gov.au", "vic.gov.au", "wa.gov.au")));
-    top3Map.put("im", new HashSet<String>(Arrays.asList("ltd.co.im", "plc.co.im")));
-    top3Map.put("no", new HashSet<String>(Arrays.asList("gs.aa.no", "gs.ah.no", "gs.bu.no",
-                "gs.fm.no", "gs.hl.no", "gs.hm.no", "gs.jan-mayen.no", "gs.mr.no", "gs.nl.no",
-                "gs.nt.no", "gs.of.no", "gs.ol.no", "gs.oslo.no", "gs.rl.no", "gs.sf.no",
-                "gs.st.no", "gs.svalbard.no", "gs.tm.no", "gs.tr.no", "gs.va.no", "gs.vf.no",
-                "bo.telemark.no", "xn--b-5ga.telemark.no", "bo.nordland.no",
-                "xn--b-5ga.nordland.no", "heroy.more-og-romsdal.no",
-                "xn--hery-ira.xn--mre-og-romsdal-qqb.no", "heroy.nordland.no",
-                "xn--hery-ira.nordland.no", "nes.akershus.no", "nes.buskerud.no",
-                "os.hedmark.no", "os.hordaland.no",
-                "sande.more-og-romsdal.no", "sande.xn--mre-og-romsdal-qqb.no",
-                "sande.vestfold.no", "valer.ostfold.no", "xn--vler-qoa.xn--stfold-9xa.no",
-                "valer.hedmark.no", "xn--vler-qoa.hedmark.no")));
-    top3Map.put("tr", new HashSet<String>(Arrays.asList("gov.nc.tr")));
-}
-
-
-    /*
-     * Return the registered part of a qualified domain
-     * name or the original if no match is found.
-     */
-    public static String getRegisteredDomain(String cname) {
-        int dot;
-
-        /*
-         * If one dot or less than just return.
-         */
-        dot = cname.lastIndexOf('.');
-        if (dot == -1)
-            return cname;
-        if (dot == 0)
-            return "";
-        if (dot == cname.length() - 1) {
-            cname = cname.substring(0, cname.length() -1);
-            dot = cname.lastIndexOf('.');
-            if (dot == -1)
-                return cname;
-            if (dot == 0)
-                return "";
-        }
-        if (dot == cname.length() - 1)
-            return "";
-
-        /*
-         * Break it up into seperate labels.
-         */
-        int second = cname.lastIndexOf('.', dot - 1);
-        if (second == -1)
-            return cname;
-        if (second == 0)
-            return "";
-        int third = cname.lastIndexOf('.', second - 1);
-        int fourth = -1;
-        if (third > 0) {
-            fourth = cname.lastIndexOf('.', third - 1);
-        }
-        int fifth = -1;
-        if (fourth > 0) {
-            fifth = cname.lastIndexOf('.', fourth - 1);
-        }
-        String s = cname.substring(dot + 1);
-        String s2 = cname.substring(second + 1, dot);
-
-        /*
-         * Look for longest matches first.
-         * XX.PVT.K12.MA.US etc.
-         */
-        if (fourth != -1 && s.equals("us") && usStateSet.contains(s2)) {
-            String s3 = cname.substring(third + 1, second);
-            String s4 = cname.substring(fourth + 1, third);
-            if (s3.equals("k12")) {
-                if (s2.equals("ma") && (s4.equals("chtr") || s4.equals("paroch"))) {
-                    return cname.substring(fifth + 1);
-                } else if (s4.equals("pvt")) {
-                    return cname.substring(fifth + 1);
-                }
-            }
-        }
-
-        /*
-         * XX.K12.MA.US.
-         */
-        String str = cname.substring(third + 1);
-        if (third != -1) {
-            Set set = top3Map.get(s);
-            if (set != null) {
-                if (set.contains(str)) {
-                    return cname.substring(fourth + 1);
-                }
-            } else if (s.equals("us") && usStateSet.contains(s2)) {
-                // check for known third level labels
-                String s3 = cname.substring(third + 1, second);
-                if (usSubStateSet.contains(s3)) {
-                    return fourth != -1? cname.substring(fourth + 1): cname;
-                } else {
-                    return cname.substring(third + 1);
-                }
-            } else if (s.equals("uk")) {
-                if (s2.equals("sch")) {
-                    return cname.substring(fourth + 1);
-                }
-            } else if (s.equals("jp")) {
-                if (jpSet.contains(s2)) {
-                    if (jp2Set.contains(str)) {
-                        return cname.substring(third + 1);
-                    }
-                    return cname.substring(fourth + 1);
-                }
-            }
-        }
-
-        /*
-         * PREF.AKITA.JP etc.
-         */
-        if (jp2Set.contains(str)) {
-            return cname.substring(third + 1);
-        }
-
-        /*
-         * XX.MA.US.
-         */
-        Set topSet = topMap.get(s);
-        if (topSet != null) {
-            if (topSet.contains(s2)) {
-                return cname.substring(third + 1);
-            }
-            if (!((s.equals("us") && usStateSet.contains(s2)) || (s.equals("jp") && jpSet.contains(s2)))) {
-                return cname.substring(second + 1);
-            }
-        } else if (top2Set.contains(s)) {
-            if (s2.equals("gov")) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (top3Set.contains(s)) {
-            if (s.equals("ad") && s2.equals("nom") ||
-                s.equals("aw") && s2.equals("com") ||
-                s.equals("be") && s2.equals("ac") ||
-                s.equals("cl") && s2.equals("gov") ||
-                s.equals("cl") && s2.equals("gob") ||
-                s.equals("fi") && s2.equals("aland") ||
-                s.equals("int") && s2.equals("eu") ||
-                s.equals("io") && s2.equals("com") ||
-                s.equals("mc") && s2.equals("tm") ||
-                s.equals("mc") && s2.equals("asso") ||
-                s.equals("vc") && s2.equals("com")) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (top4Set.contains(s)) {
-            if (s2.equals("com") || s2.equals("edu") || s2.equals("gov") ||
-                s2.equals("net") || s2.equals("org")) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (top5Set.contains(s)) {
-            return cname.substring(third + 1);
-        }
-
-        /*
-         * BB.AA exception cases.
-         */
-        if (s.equals("tr")) {
-            if (!s2.equals("nic") && !s2.equals("tsk")) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (s.equals("uk")) {
-            if (!ukSet.contains(s2)) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (s.equals("ar")) {
-            if (!arSet.contains(s2)) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        } else if (s.equals("om")) {
-            if (!omSet.contains(s2)) {
-                return cname.substring(third + 1);
-            }
-            return cname.substring(second + 1);
-        }
-
-        /*
-         * XX.AA
-         */
-        if (top1Set.contains(s)) {
-            return cname.substring(second + 1);
-        }
-
-        /*
-         * Nothing matched so we can't shorten the string.
-         */
-        return cname;
-     }
-}
diff --git a/ojluni/src/main/java/sun/net/TransferProtocolClient.java b/ojluni/src/main/java/sun/net/TransferProtocolClient.java
deleted file mode 100644
index 2b74b62..0000000
--- a/ojluni/src/main/java/sun/net/TransferProtocolClient.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net;
-
-import java.lang.StringIndexOutOfBoundsException;
-import java.io.*;
-import java.util.Vector;
-import sun.net.NetworkClient;
-
-/**
- * This class implements that basic intefaces of transfer protocols.
- * It is used by subclasses implementing specific protocols.
- *
- * @author      Jonathan Payne
- * @see         sun.net.ftp.FtpClient
- * @see         sun.net.nntp.NntpClient
- */
-
-public class TransferProtocolClient extends NetworkClient {
-    static final boolean debug = false;
-
-    /** Array of strings (usually 1 entry) for the last reply
-        from the server. */
-    protected Vector    serverResponse = new Vector(1);
-
-    /** code for last reply */
-    protected int       lastReplyCode;
-
-
-    /**
-     * Pulls the response from the server and returns the code as a
-     * number. Returns -1 on failure.
-     */
-    public int readServerResponse() throws IOException {
-        StringBuffer    replyBuf = new StringBuffer(32);
-        int             c;
-        int             continuingCode = -1;
-        int             code;
-        String          response;
-
-        serverResponse.setSize(0);
-        while (true) {
-            while ((c = serverInput.read()) != -1) {
-                if (c == '\r') {
-                    if ((c = serverInput.read()) != '\n')
-                        replyBuf.append('\r');
-                }
-                replyBuf.append((char)c);
-                if (c == '\n')
-                    break;
-            }
-            response = replyBuf.toString();
-            replyBuf.setLength(0);
-            if (debug) {
-                System.out.print(response);
-            }
-
-            if (response.length() == 0) {
-                code = -1;
-            } else {
-                try {
-                    code = Integer.parseInt(response.substring(0, 3));
-                } catch (NumberFormatException e) {
-                    code = -1;
-                } catch (StringIndexOutOfBoundsException e) {
-                    /* this line doesn't contain a response code, so
-                       we just completely ignore it */
-                    continue;
-                }
-            }
-            serverResponse.addElement(response);
-            if (continuingCode != -1) {
-                /* we've seen a XXX- sequence */
-                if (code != continuingCode ||
-                    (response.length() >= 4 && response.charAt(3) == '-')) {
-                    continue;
-                } else {
-                    /* seen the end of code sequence */
-                    continuingCode = -1;
-                    break;
-                }
-            } else if (response.length() >= 4 && response.charAt(3) == '-') {
-                continuingCode = code;
-                continue;
-            } else {
-                break;
-            }
-        }
-
-        return lastReplyCode = code;
-    }
-
-    /** Sends command <i>cmd</i> to the server. */
-    public void sendServer(String cmd) {
-        serverOutput.print(cmd);
-        if (debug) {
-            System.out.print("Sending: " + cmd);
-        }
-    }
-
-    /** converts the server response into a string. */
-    public String getResponseString() {
-        return (String) serverResponse.elementAt(0);
-    }
-
-    /** Returns all server response strings. */
-    public Vector getResponseStrings() {
-        return serverResponse;
-    }
-
-    /** standard constructor to host <i>host</i>, port <i>port</i>. */
-    public TransferProtocolClient(String host, int port) throws IOException {
-        super(host, port);
-    }
-
-    /** creates an uninitialized instance of this class. */
-    public TransferProtocolClient() {}
-}
diff --git a/ojluni/src/main/java/sun/net/smtp/SmtpClient.java b/ojluni/src/main/java/sun/net/smtp/SmtpClient.java
deleted file mode 100644
index d97b16a..0000000
--- a/ojluni/src/main/java/sun/net/smtp/SmtpClient.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.smtp;
-
-import java.util.StringTokenizer;
-import java.io.*;
-import java.net.*;
-import sun.net.TransferProtocolClient;
-
-/**
- * This class implements the SMTP client.
- * You can send a piece of mail by creating a new SmtpClient, calling
- * the "to" method to add destinations, calling "from" to name the
- * sender, calling startMessage to return a stream to which you write
- * the message (with RFC733 headers) and then you finally close the Smtp
- * Client.
- *
- * @author      James Gosling
- */
-
-public class SmtpClient extends TransferProtocolClient {
-
-    String mailhost;
-    SmtpPrintStream message;
-
-    /**
-     * issue the QUIT command to the SMTP server and close the connection.
-     */
-    public void closeServer() throws IOException {
-        if (serverIsOpen()) {
-            closeMessage();
-            issueCommand("QUIT\r\n", 221);
-            super.closeServer();
-        }
-    }
-
-    void issueCommand(String cmd, int expect) throws IOException {
-        sendServer(cmd);
-        int reply;
-        while ((reply = readServerResponse()) != expect)
-            if (reply != 220) {
-                throw new SmtpProtocolException(getResponseString());
-            }
-    }
-
-    private void toCanonical(String s) throws IOException {
-        if (s.startsWith("<"))
-            issueCommand("rcpt to: " + s + "\r\n", 250);
-        else
-            issueCommand("rcpt to: <" + s + ">\r\n", 250);
-    }
-
-    public void to(String s) throws IOException {
-        int st = 0;
-        int limit = s.length();
-        int pos = 0;
-        int lastnonsp = 0;
-        int parendepth = 0;
-        boolean ignore = false;
-        while (pos < limit) {
-            int c = s.charAt(pos);
-            if (parendepth > 0) {
-                if (c == '(')
-                    parendepth++;
-                else if (c == ')')
-                    parendepth--;
-                if (parendepth == 0)
-                    if (lastnonsp > st)
-                        ignore = true;
-                    else
-                        st = pos + 1;
-            } else if (c == '(')
-                parendepth++;
-            else if (c == '<')
-                st = lastnonsp = pos + 1;
-            else if (c == '>')
-                ignore = true;
-            else if (c == ',') {
-                if (lastnonsp > st)
-                    toCanonical(s.substring(st, lastnonsp));
-                st = pos + 1;
-                ignore = false;
-            } else {
-                if (c > ' ' && !ignore)
-                    lastnonsp = pos + 1;
-                else if (st == pos)
-                    st++;
-            }
-            pos++;
-        }
-        if (lastnonsp > st)
-            toCanonical(s.substring(st, lastnonsp));
-    }
-
-    public void from(String s) throws IOException {
-        if (s.startsWith("<"))
-            issueCommand("mail from: " + s + "\r\n", 250);
-        else
-            issueCommand("mail from: <" + s + ">\r\n", 250);
-    }
-
-    /** open a SMTP connection to host <i>host</i>. */
-    private void openServer(String host) throws IOException {
-        mailhost = host;
-        openServer(mailhost, 25);
-        issueCommand("helo "+InetAddress.getLocalHost().getHostName()+"\r\n", 250);
-    }
-
-    public PrintStream startMessage() throws IOException {
-        issueCommand("data\r\n", 354);
-        try {
-            message = new SmtpPrintStream(serverOutput, this);
-        } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding+" encoding not found");
-        }
-        return message;
-    }
-
-    void closeMessage() throws IOException {
-        if (message != null)
-            message.close();
-    }
-
-    /** New SMTP client connected to host <i>host</i>. */
-    public SmtpClient (String host) throws IOException {
-        super();
-        if (host != null) {
-            try {
-                openServer(host);
-                mailhost = host;
-                return;
-            } catch(Exception e) {
-            }
-        }
-        try {
-            String s;
-            mailhost = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction("mail.host"));
-            if (mailhost != null) {
-                openServer(mailhost);
-                return;
-            }
-        } catch(Exception e) {
-        }
-        try {
-            mailhost = "localhost";
-            openServer(mailhost);
-        } catch(Exception e) {
-            mailhost = "mailhost";
-            openServer(mailhost);
-        }
-    }
-
-    /** Create an uninitialized SMTP client. */
-    public SmtpClient () throws IOException {
-        this(null);
-    }
-
-    public SmtpClient(int to) throws IOException {
-        super();
-        setConnectTimeout(to);
-        try {
-            String s;
-            mailhost = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction("mail.host"));
-            if (mailhost != null) {
-                openServer(mailhost);
-                return;
-            }
-        } catch(Exception e) {
-        }
-        try {
-            mailhost = "localhost";
-            openServer(mailhost);
-        } catch(Exception e) {
-            mailhost = "mailhost";
-            openServer(mailhost);
-        }
-    }
-
-    public String getMailHost() {
-        return mailhost;
-    }
-
-    String getEncoding () {
-        return encoding;
-    }
-}
-
-class SmtpPrintStream extends java.io.PrintStream {
-    private SmtpClient target;
-    private int lastc = '\n';
-
-    SmtpPrintStream (OutputStream fos, SmtpClient cl) throws UnsupportedEncodingException {
-        super(fos, false, cl.getEncoding());
-        target = cl;
-    }
-
-    public void close() {
-        if (target == null)
-            return;
-        if (lastc != '\n') {
-            write('\n');
-        }
-        try {
-            target.issueCommand(".\r\n", 250);
-            target.message = null;
-            out = null;
-            target = null;
-        } catch (IOException e) {
-        }
-    }
-
-    public void write(int b) {
-        try {
-            // quote a dot at the beginning of a line
-            if (lastc == '\n' && b == '.') {
-                out.write('.');
-            }
-
-            // translate NL to CRLF
-            if (b == '\n' && lastc != '\r') {
-                out.write('\r');
-            }
-            out.write(b);
-            lastc = b;
-        } catch (IOException e) {
-        }
-    }
-
-    public void write(byte b[], int off, int len) {
-        try {
-            int lc = lastc;
-            while (--len >= 0) {
-                int c = b[off++];
-
-                // quote a dot at the beginning of a line
-                if (lc == '\n' && c == '.')
-                    out.write('.');
-
-                // translate NL to CRLF
-                if (c == '\n' && lc != '\r') {
-                    out.write('\r');
-                }
-                out.write(c);
-                lc = c;
-            }
-            lastc = lc;
-        } catch (IOException e) {
-        }
-    }
-    public void print(String s) {
-        int len = s.length();
-        for (int i = 0; i < len; i++) {
-            write(s.charAt(i));
-        }
-    }
-}
diff --git a/ojluni/src/main/java/sun/net/smtp/SmtpProtocolException.java b/ojluni/src/main/java/sun/net/smtp/SmtpProtocolException.java
deleted file mode 100644
index d744ebb..0000000
--- a/ojluni/src/main/java/sun/net/smtp/SmtpProtocolException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.smtp;
-
-import java.io.IOException;
-
-/**
- * This exeception is thrown when unexpected results are returned during
- * an SMTP session.
- */
-public class SmtpProtocolException extends IOException {
-    private static final long serialVersionUID = -7547136771133814908L;
-
-    SmtpProtocolException(String s) {
-        super(s);
-    }
-}
diff --git a/ojluni/src/main/java/sun/net/www/HeaderParser.java b/ojluni/src/main/java/sun/net/www/HeaderParser.java
deleted file mode 100644
index a16b267..0000000
--- a/ojluni/src/main/java/sun/net/www/HeaderParser.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www;
-
-import java.util.Iterator;
-
-/* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
- * sensibly:
- * From a String like: 'timeout=15, max=5'
- * create an array of Strings:
- * { {"timeout", "15"},
- *   {"max", "5"}
- * }
- * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
- * create one like (no quotes in literal):
- * { {"basic", null},
- *   {"realm", "FuzzFace"}
- *   {"foo", "Biz Bar Baz"}
- * }
- * keys are converted to lower case, vals are left as is....
- *
- * @author Dave Brown
- */
-
-
-public class HeaderParser {
-
-    /* table of key/val pairs */
-    String raw;
-    String[][] tab;
-    int nkeys;
-    int asize = 10; // initial size of array is 10
-
-    public HeaderParser(String raw) {
-        this.raw = raw;
-        tab = new String[asize][2];
-        parse();
-    }
-
-    private HeaderParser () {
-    }
-
-    /**
-     * create a new HeaderParser from this, whose keys (and corresponding values)
-     * range from "start" to "end-1"
-     */
-    public HeaderParser subsequence (int start, int end) {
-        if (start == 0 && end == nkeys) {
-            return this;
-        }
-        if (start < 0 || start >= end || end > nkeys)
-            throw new IllegalArgumentException ("invalid start or end");
-        HeaderParser n = new HeaderParser ();
-        n.tab = new String [asize][2];
-        n.asize = asize;
-        System.arraycopy (tab, start, n.tab, 0, (end-start));
-        n.nkeys= (end-start);
-        return n;
-    }
-
-    private void parse() {
-
-        if (raw != null) {
-            raw = raw.trim();
-            char[] ca = raw.toCharArray();
-            int beg = 0, end = 0, i = 0;
-            boolean inKey = true;
-            boolean inQuote = false;
-            int len = ca.length;
-            while (end < len) {
-                char c = ca[end];
-                if ((c == '=') && !inQuote) { // end of a key
-                    tab[i][0] = new String(ca, beg, end-beg).toLowerCase();
-                    inKey = false;
-                    end++;
-                    beg = end;
-                } else if (c == '\"') {
-                    if (inQuote) {
-                        tab[i++][1]= new String(ca, beg, end-beg);
-                        inQuote=false;
-                        do {
-                            end++;
-                        } while (end < len && (ca[end] == ' ' || ca[end] == ','));
-                        inKey=true;
-                        beg=end;
-                    } else {
-                        inQuote=true;
-                        end++;
-                        beg=end;
-                    }
-                } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
-                    if (inQuote) {
-                        end++;
-                        continue;
-                    } else if (inKey) {
-                        tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase();
-                    } else {
-                        tab[i++][1] = (new String(ca, beg, end-beg));
-                    }
-                    while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
-                        end++;
-                    }
-                    inKey = true;
-                    beg = end;
-                } else {
-                    end++;
-                }
-                if (i == asize) {
-                    asize = asize * 2;
-                    String[][] ntab = new String[asize][2];
-                    System.arraycopy (tab, 0, ntab, 0, tab.length);
-                    tab = ntab;
-                }
-            }
-            // get last key/val, if any
-            if (--end > beg) {
-                if (!inKey) {
-                    if (ca[end] == '\"') {
-                        tab[i++][1] = (new String(ca, beg, end-beg));
-                    } else {
-                        tab[i++][1] = (new String(ca, beg, end-beg+1));
-                    }
-                } else {
-                    tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
-                }
-            } else if (end == beg) {
-                if (!inKey) {
-                    if (ca[end] == '\"') {
-                        tab[i++][1] = String.valueOf(ca[end-1]);
-                    } else {
-                        tab[i++][1] = String.valueOf(ca[end]);
-                    }
-                } else {
-                    tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
-                }
-            }
-            nkeys=i;
-        }
-
-    }
-
-    public String findKey(int i) {
-        if (i < 0 || i > asize)
-            return null;
-        return tab[i][0];
-    }
-
-    public String findValue(int i) {
-        if (i < 0 || i > asize)
-            return null;
-        return tab[i][1];
-    }
-
-    public String findValue(String key) {
-        return findValue(key, null);
-    }
-
-    public String findValue(String k, String Default) {
-        if (k == null)
-            return Default;
-        k = k.toLowerCase();
-        for (int i = 0; i < asize; ++i) {
-            if (tab[i][0] == null) {
-                return Default;
-            } else if (k.equals(tab[i][0])) {
-                return tab[i][1];
-            }
-        }
-        return Default;
-    }
-
-    class ParserIterator implements Iterator {
-        int index;
-        boolean returnsValue; // or key
-
-        ParserIterator (boolean returnValue) {
-            returnsValue = returnValue;
-        }
-        public boolean hasNext () {
-            return index<nkeys;
-        }
-        public Object next () {
-            return tab[index++][returnsValue?1:0];
-        }
-        public void remove () {
-            throw new UnsupportedOperationException ("remove not supported");
-        }
-    }
-
-    public Iterator keys () {
-        return new ParserIterator (false);
-    }
-
-    public Iterator values () {
-        return new ParserIterator (true);
-    }
-
-    public String toString () {
-        Iterator k = keys();
-        StringBuffer sbuf = new StringBuffer();
-        sbuf.append ("{size="+asize+" nkeys="+nkeys+" ");
-        for (int i=0; k.hasNext(); i++) {
-            String key = (String)k.next();
-            String val = findValue (i);
-            if (val != null && "".equals (val)) {
-                val = null;
-            }
-            sbuf.append (" {"+key+(val==null?"":","+val)+"}");
-            if (k.hasNext()) {
-                sbuf.append (",");
-            }
-        }
-        sbuf.append (" }");
-        return new String (sbuf);
-    }
-
-    public int findInt(String k, int Default) {
-        try {
-            return Integer.parseInt(findValue(k, String.valueOf(Default)));
-        } catch (Throwable t) {
-            return Default;
-        }
-    }
-    /*
-    public static void main(String[] a) throws Exception {
-        System.out.print("enter line to parse> ");
-        System.out.flush();
-        DataInputStream dis = new DataInputStream(System.in);
-        String line = dis.readLine();
-        HeaderParser p = new HeaderParser(line);
-        for (int i = 0; i < asize; ++i) {
-            if (p.findKey(i) == null) break;
-            String v = p.findValue(i);
-            System.out.println(i + ") " +p.findKey(i) + "="+v);
-        }
-        System.out.println("Done!");
-
-    }
-    */
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java b/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java
index e7e6ad0..410ba0a 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java
@@ -45,11 +45,12 @@
 /* URL jar file is a common JarFile subtype used for JarURLConnection */
 public class URLJarFile extends JarFile {
 
-    /*
-     * Interface to be able to call retrieve() in plugin if
-     * this variable is set.
-     */
-    private static URLJarFileCallBack callback = null;
+// Android-changed: Removed setCallBack(URLJarFileCallBack) and field callback (dead code).
+//    /*
+//     * Interface to be able to call retrieve() in plugin if
+//     * this variable is set.
+//     */
+//    private static URLJarFileCallBack callback = null;
 
     /* Controller of the Jar File's closing */
     private URLJarFileCloseController closeController = null;
@@ -195,17 +196,18 @@
      * cached JAR file object.
      */
      private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
-        /*
-         * See if interface is set, then call retrieve function of the class
-         * that implements URLJarFileCallBack interface (sun.plugin - to
-         * handle the cache failure for JARJAR file.)
-         */
-        if (callback != null)
-        {
-            return callback.retrieve(url);
-        }
-
-        else
+// Android-changed: Removed setCallBack(URLJarFileCallBack) and field callback (dead code).
+//        /*
+//         * See if interface is set, then call retrieve function of the class
+//         * that implements URLJarFileCallBack interface (sun.plugin - to
+//         * handle the cache failure for JARJAR file.)
+//         */
+//        if (callback != null)
+//        {
+//            return callback.retrieve(url);
+//        }
+//
+//        else
         {
 
             JarFile result = null;
@@ -239,15 +241,15 @@
         }
     }
 
-    /*
-     * Set the call back interface to call retrive function in sun.plugin
-     * package if plugin is running.
-     */
-    public static void setCallBack(URLJarFileCallBack cb)
-    {
-        callback = cb;
-    }
-
+// Android-changed: Removed setCallBack(URLJarFileCallBack) and field callback (dead code).
+//    /*
+//     * Set the call back interface to call retrive function in sun.plugin
+//     * package if plugin is running.
+//     */
+//    public static void setCallBack(URLJarFileCallBack cb)
+//    {
+//        callback = cb;
+//    }
 
     private class URLJarFileEntry extends JarEntry {
         private JarEntry je;
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java b/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java
deleted file mode 100644
index d55aeaf..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.jar;
-
-import java.io.*;
-import java.net.*;
-import java.util.jar.*;
-
-
-/*
- * This interface is used to call back to sun.plugin package.
- */
-public interface URLJarFileCallBack
-{
-        public JarFile retrieve (URL url) throws IOException;
-}
diff --git a/ojluni/src/main/java/sun/util/locale/provider/CalendarDataUtility.java b/ojluni/src/main/java/sun/util/locale/provider/CalendarDataUtility.java
index 509e760..30df227 100644
--- a/ojluni/src/main/java/sun/util/locale/provider/CalendarDataUtility.java
+++ b/ojluni/src/main/java/sun/util/locale/provider/CalendarDataUtility.java
@@ -43,6 +43,11 @@
  */
 public class CalendarDataUtility {
 
+    private static final String ISLAMIC_CALENDAR = "islamic";
+    private static final String GREGORIAN_CALENDAR = "gregorian";
+    private static final String BUDDHIST_CALENDAR = "buddhist";
+    private static final String JAPANESE_CALENDAR = "japanese";
+
     // No instantiation
     private CalendarDataUtility() {
     }
@@ -53,6 +58,25 @@
     public static String retrieveFieldValueName(String id, int field, int value, int style,
             Locale locale) {
         // Android-changed: delegate to ICU.
+        if (field == Calendar.ERA) {
+            // For era the field value does not always equal the index into the names array.
+            switch (normalizeCalendarType(id)) {
+                // These calendars have only one era, but represented it by the value 1.
+                case BUDDHIST_CALENDAR:
+                case ISLAMIC_CALENDAR:
+                    value -= 1;
+                    break;
+                case JAPANESE_CALENDAR:
+                    // CLDR contains full data for historical eras, java.time only supports the 4
+                    // modern eras and numbers the modern eras starting with 1 (MEIJI). There are
+                    // 232 historical eras in CLDR/ICU so to get the real offset, we add 231.
+                    value += 231;
+                    break;
+                default:
+                    // Other eras use 0-based values (e.g. 0=BCE, 1=CE for gregorian).
+                    break;
+            }
+        }
         if (value < 0) {
             return null;
         }
@@ -69,14 +93,60 @@
         return retrieveFieldValueName(id, field, value, style, locale);
     }
 
+    // ALL_STYLES implies SHORT_FORMAT and all of these values.
+    private static int[] REST_OF_STYLES = {
+            SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE,
+            NARROW_FORMAT, NARROW_STANDALONE
+    };
+
     public static Map<String, Integer> retrieveFieldValueNames(String id, int field, int style,
             Locale locale) {
-        // TODO: support ALL_STYLES
         // Android-changed: delegate to ICU.
+        Map<String, Integer> names;
+        if (style == ALL_STYLES) {
+            names = retrieveFieldValueNamesImpl(id, field, SHORT_FORMAT, locale);
+            for (int st : REST_OF_STYLES) {
+                names.putAll(retrieveFieldValueNamesImpl(id, field, st, locale));
+            }
+        } else {
+            // specific style
+            names = retrieveFieldValueNamesImpl(id, field, style, locale);
+        }
+        return names.isEmpty() ? null : names;
+    }
+
+    private static Map<String, Integer> retrieveFieldValueNamesImpl(String id, int field, int style,
+            Locale locale) {
         String[] names = getNames(id, field, style, locale);
+        int skipped = 0;
+        int offset = 0;
+        if (field == Calendar.ERA) {
+            // See retrieveFieldValueName() for explanation of this code and the values used.
+            switch (normalizeCalendarType(id)) {
+                case BUDDHIST_CALENDAR:
+                case ISLAMIC_CALENDAR:
+                    offset = 1;
+                    break;
+                case JAPANESE_CALENDAR:
+                    skipped = 232;
+                    offset = -231;
+                    break;
+                default:
+                    break;
+            }
+        }
         Map<String, Integer> result = new LinkedHashMap<>();
-        for (int i = 0; i < names.length; i++) {
-            result.put(names[i], i);
+        for (int i = skipped; i < names.length; i++) {
+            if (names[i].isEmpty()) {
+                continue;
+            }
+
+            if (result.put(names[i], i + offset) != null) {
+                // Duplicate names indicate that the names would be ambiguous. Skip this style for
+                // ALL_STYLES. In other cases this results in null being returned in
+                // retrieveValueNames(), which is required by Calendar.getDisplayNames().
+                return new LinkedHashMap<>();
+            }
         }
         return result;
     }
@@ -156,14 +226,14 @@
         }
     }
 
-    static String normalizeCalendarType(String requestID) {
+    private static String normalizeCalendarType(String requestID) {
         String type;
         // Android-changed: normalize "gregory" to "gregorian", not the other way around.
         // See android.icu.text.DateFormatSymbols.CALENDAR_CLASSES for reference.
         if (requestID.equals("gregory") || requestID.equals("iso8601")) {
-            type = "gregorian";
-        } else if (requestID.startsWith("islamic")) {
-            type = "islamic";
+            type = GREGORIAN_CALENDAR;
+        } else if (requestID.startsWith(ISLAMIC_CALENDAR)) {
+            type = ISLAMIC_CALENDAR;
         } else {
             type = requestID;
         }
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
index ee3898e..3d89db5 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
@@ -106,7 +106,7 @@
 import java.util.List;
 import java.util.Locale;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -121,10 +121,13 @@
     private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
 
-    private Instant TEST_12345_123456789;
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static Instant TEST_12345_123456789;
 
-    @BeforeMethod
-    public void setUp() {
+    @BeforeClass
+    public static void setUp() {
         TEST_12345_123456789 = Instant.ofEpochSecond(12345, 123456789);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKLocalDate.java b/ojluni/src/test/java/time/tck/java/time/TCKLocalDate.java
index 02e2f07..5670a46 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKLocalDate.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKLocalDate.java
@@ -121,7 +121,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import test.java.time.MockSimplePeriod;
@@ -138,16 +138,19 @@
     private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
     private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
 
-    private LocalDate TEST_2007_07_15;
-    private long MAX_VALID_EPOCHDAYS;
-    private long MIN_VALID_EPOCHDAYS;
-    private LocalDate MAX_DATE;
-    private LocalDate MIN_DATE;
-    private Instant MAX_INSTANT;
-    private Instant MIN_INSTANT;
+    // Android changed: These wer originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static LocalDate TEST_2007_07_15;
+    private static long MAX_VALID_EPOCHDAYS;
+    private static long MIN_VALID_EPOCHDAYS;
+    private static LocalDate MAX_DATE;
+    private static LocalDate MIN_DATE;
+    private static Instant MAX_INSTANT;
+    private static Instant MIN_INSTANT;
 
-    @BeforeMethod
-    public void setUp() {
+    @BeforeClass
+    public static void setUp() {
         TEST_2007_07_15 = LocalDate.of(2007, 7, 15);
 
         LocalDate max = LocalDate.MAX;
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKLocalTime.java b/ojluni/src/test/java/time/tck/java/time/TCKLocalTime.java
index f79e8fc..a695803 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKLocalTime.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKLocalTime.java
@@ -126,7 +126,7 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -139,7 +139,10 @@
     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
     private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
 
-    private LocalTime TEST_12_30_40_987654321;
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static LocalTime TEST_12_30_40_987654321;
 
     private static final TemporalUnit[] INVALID_UNITS;
     static {
@@ -147,8 +150,8 @@
         INVALID_UNITS = set.toArray(new TemporalUnit[set.size()]);
     }
 
-    @BeforeMethod
-    public void setUp() {
+    @BeforeClass
+    public static void setUp() {
         TEST_12_30_40_987654321 = LocalTime.of(12, 30, 40, 987654321);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKMonthDay.java b/ojluni/src/test/java/time/tck/java/time/TCKMonthDay.java
index 99a7116..a9214e4 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKMonthDay.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKMonthDay.java
@@ -94,7 +94,7 @@
 import java.util.List;
 import java.util.Set;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -104,10 +104,13 @@
 @Test
 public class TCKMonthDay extends AbstractDateTimeTest {
 
-    private MonthDay TEST_07_15;
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static MonthDay TEST_07_15;
 
-    @BeforeMethod
-    public void setUp() {
+    @BeforeClass
+    public static void setUp() {
         TEST_07_15 = MonthDay.of(7, 15);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKOffsetDateTime.java b/ojluni/src/test/java/time/tck/java/time/TCKOffsetDateTime.java
index b77b7a8..4849f06 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKOffsetDateTime.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKOffsetDateTime.java
@@ -139,7 +139,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import test.java.time.MockSimplePeriod;
@@ -156,10 +156,14 @@
     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
     private static final ZoneOffset OFFSET_MONE = ZoneOffset.ofHours(-1);
     private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
-    private OffsetDateTime TEST_2008_6_30_11_30_59_000000500;
 
-    @BeforeMethod
-    public void setUp() {
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static OffsetDateTime TEST_2008_6_30_11_30_59_000000500;
+
+    @BeforeClass
+    public static void setUp() {
         TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 500, OFFSET_PONE);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKOffsetTime.java b/ojluni/src/test/java/time/tck/java/time/TCKOffsetTime.java
index d373be4..b195492 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKOffsetTime.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKOffsetTime.java
@@ -122,7 +122,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import test.java.time.MockSimplePeriod;
@@ -137,10 +137,14 @@
     private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
     private static final LocalDate DATE = LocalDate.of(2008, 12, 3);
-    private OffsetTime TEST_11_30_59_500_PONE;
 
-    @BeforeMethod
-    public void setUp() {
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static OffsetTime TEST_11_30_59_500_PONE;
+
+    @BeforeClass
+    public static void setUp() {
         TEST_11_30_59_500_PONE = OffsetTime.of(11, 30, 59, 500, OFFSET_PONE);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKYearMonth.java b/ojluni/src/test/java/time/tck/java/time/TCKYearMonth.java
index e922f72..1964db6 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKYearMonth.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKYearMonth.java
@@ -110,7 +110,7 @@
 import java.util.List;
 import java.util.Set;
 
-import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -120,10 +120,13 @@
 @Test
 public class TCKYearMonth extends AbstractDateTimeTest {
 
-    private YearMonth TEST_2008_06;
+    // Android changed: This was originally non-static and initialized in @BeforeMethod,
+    // but @BeforeMethod is run after @DataProvider methods are run, so it only worked by accident,
+    // since multiple test methods were run and the first one did not require this value.
+    private static YearMonth TEST_2008_06;
 
-    @BeforeMethod
-    public void setUp() {
+    @BeforeClass
+    public static void setUp() {
         TEST_2008_06 = YearMonth.of(2008, 6);
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/format/TCKFormatStyle.java b/ojluni/src/test/java/time/tck/java/time/format/TCKFormatStyle.java
index 1175673..bd38d51 100644
--- a/ojluni/src/test/java/time/tck/java/time/format/TCKFormatStyle.java
+++ b/ojluni/src/test/java/time/tck/java/time/format/TCKFormatStyle.java
@@ -93,15 +93,16 @@
     @DataProvider(name="formatStyle")
     Object[][] data_formatStyle() {
         return new Object[][] {
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.FULL, "Tuesday, October 2, 2001 1:02:03 AM CEST Europe/Paris"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.LONG, "October 2, 2001 1:02:03 AM CEST Europe/Paris"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.MEDIUM, "Oct 2, 2001 1:02:03 AM Europe/Paris"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.SHORT, "10/2/01 1:02 AM Europe/Paris"},
+                // Android-changed: date/time patterns changed in new CLDR; adapt to UK locale.
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.FULL, "Tuesday, 2 October 2001 at 01:02:03 Central European Summer Time Europe/Paris"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.LONG, "2 October 2001 at 01:02:03 CEST Europe/Paris"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.MEDIUM, "2 Oct 2001, 01:02:03 Europe/Paris"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.SHORT, "02/10/2001, 01:02 Europe/Paris"},
 
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.FULL, "Tuesday, October 2, 2001 1:02:03 AM +02:00 +02:00"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.LONG, "October 2, 2001 1:02:03 AM +02:00 +02:00"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.MEDIUM, "Oct 2, 2001 1:02:03 AM +02:00"},
-                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.SHORT, "10/2/01 1:02 AM +02:00"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.FULL, "Tuesday, 2 October 2001 at 01:02:03 +02:00 +02:00"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.LONG, "2 October 2001 at 01:02:03 +02:00 +02:00"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.MEDIUM, "2 Oct 2001, 01:02:03 +02:00"},
+                {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.SHORT, "02/10/2001, 01:02 +02:00"},
         };
     }
 
@@ -109,7 +110,8 @@
     public void test_formatStyle(Temporal temporal, FormatStyle style, String formattedStr) {
         DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
         DateTimeFormatter formatter = builder.appendLocalized(style, style).appendLiteral(" ").appendZoneOrOffsetId().toFormatter();
-        formatter = formatter.withLocale(Locale.US);
+        // Android-changed: Use a locale that actually uses "CEST" as short form of Europe/Paris.
+        formatter = formatter.withLocale(Locale.UK);
         assertEquals(formatter.format(temporal), formattedStr);
     }
 }
diff --git a/ojluni/src/test/java/time/tck/java/time/zone/TCKZoneRules.java b/ojluni/src/test/java/time/tck/java/time/zone/TCKZoneRules.java
index 19f8239..dc4860e 100644
--- a/ojluni/src/test/java/time/tck/java/time/zone/TCKZoneRules.java
+++ b/ojluni/src/test/java/time/tck/java/time/zone/TCKZoneRules.java
@@ -372,7 +372,8 @@
 
         ZoneOffsetTransitionRule in = rules.get(0);
         assertEquals(in.getMonth(), Month.MARCH);
-        assertEquals(in.getDayOfMonthIndicator(), 25);  // optimized from -1
+        // Android changed: check for -1, which matches the data, we don't do the "optimization"
+        assertEquals(in.getDayOfMonthIndicator(), -1);  // optimized from -1
         assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY);
         assertEquals(in.getLocalTime(), LocalTime.of(1, 0));
         assertEquals(in.getTimeDefinition(), TimeDefinition.UTC);
@@ -382,7 +383,8 @@
 
         ZoneOffsetTransitionRule out = rules.get(1);
         assertEquals(out.getMonth(), Month.OCTOBER);
-        assertEquals(out.getDayOfMonthIndicator(), 25);  // optimized from -1
+        // Android changed: check for -1, which matches the data, we don't do the "optimization"
+        assertEquals(out.getDayOfMonthIndicator(), -1);  // optimized from -1
         assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY);
         assertEquals(out.getLocalTime(), LocalTime.of(1, 0));
         assertEquals(out.getTimeDefinition(), TimeDefinition.UTC);
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestServiceLoader.java b/ojluni/src/test/java/time/test/java/time/chrono/TestServiceLoader.java
index b64f8f4..2e65b8e 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestServiceLoader.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestServiceLoader.java
@@ -77,7 +77,10 @@
     @Test
     public void test_copticServiceLoader() {
         Map<String, Chronology> chronos = new HashMap<>();
-        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class, null);
+        // Android-changed: This test assumes that the system classloader sees all test classes.
+        // That assumption is untrue, when run in CTS. Use this class's classloader instead.
+        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class,
+                getClass().getClassLoader());
         for (Chronology chrono : loader) {
             chronos.put(chrono.getId(), chrono);
         }
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java
index 16a7d6e..a13630a 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java
@@ -903,60 +903,61 @@
     //-----------------------------------------------------------------------
     @DataProvider(name="localePatterns")
     Object[][] localizedDateTimePatterns() {
+        // Android-changed: Adapt for changes since old CLDR version this tests were written for.
         return new Object[][] {
-            {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, yyyy h:mm:ss a z"},
-            {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "MMMM d, yyyy h:mm:ss a z"},
-            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "MMM d, yyyy h:mm:ss a"},
-            {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "M/d/yy h:mm a"},
-            {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, yyyy"},
-            {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.US, "MMMM d, yyyy"},
-            {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.US, "MMM d, yyyy"},
+            {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, y 'at' h:mm:ss a zzzz"},
+            {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "MMMM d, y 'at' h:mm:ss a z"},
+            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "MMM d, y, h:mm:ss a"},
+            {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "M/d/yy, h:mm a"},
+            {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, y"},
+            {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.US, "MMMM d, y"},
+            {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.US, "MMM d, y"},
             {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.US, "M/d/yy"},
-            {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a z"},
+            {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a zzzz"},
             {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a z"},
             {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a"},
             {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "h:mm a"},
 
             // French Locale and ISO Chronology
-            {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM yyyy HH' h 'mm z"},
-            {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM yyyy HH:mm:ss z"},
-            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM yyyy HH:mm:ss"},
-            {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/yy HH:mm"},
-            {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM yyyy"},
-            {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM yyyy"},
-            {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM yyyy"},
-            {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/yy"},
-            {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "HH' h 'mm z"},
+            {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y 'à' HH:mm:ss zzzz"},
+            {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y 'à' HH:mm:ss z"},
+            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y 'à' HH:mm:ss"},
+            {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y HH:mm"},
+            {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y"},
+            {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y"},
+            {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y"},
+            {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y"},
+            {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss zzzz"},
             {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss z"},
             {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss"},
             {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm"},
 
             // Japanese Locale and JapaneseChronology
-            {FormatStyle.FULL, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy'\u5e74'M'\u6708'd'\u65e5' H'\u6642'mm'\u5206'ss'\u79d2' z"},
-            {FormatStyle.LONG, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd H:mm:ss z"},
-            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd H:mm:ss"},
-            {FormatStyle.SHORT, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd H:mm"},
-            {FormatStyle.FULL, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy'\u5e74'M'\u6708'd'\u65e5'"},
-            {FormatStyle.LONG, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd"},
-            {FormatStyle.MEDIUM, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd"},
-            {FormatStyle.SHORT, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy.MM.dd"},
-            {null, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H'\u6642'mm'\u5206'ss'\u79d2' z"},
+            {FormatStyle.FULL, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE H\u6642mm\u5206ss\u79d2 zzzz"},
+            {FormatStyle.LONG, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss z"},
+            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss"},
+            {FormatStyle.SHORT, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d H:mm"},
+            {FormatStyle.FULL, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE"},
+            {FormatStyle.LONG, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"},
+            {FormatStyle.MEDIUM, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"},
+            {FormatStyle.SHORT, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d"},
+            {null, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H\u6642mm\u5206ss\u79d2 zzzz"},
             {null, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss z"},
             {null, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss"},
             {null, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm"},
 
             // Chinese Local and Chronology
-            {FormatStyle.FULL, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE ahh'\u65f6'mm'\u5206'ss'\u79d2' z"},
-            {FormatStyle.LONG, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 ahh'\u65f6'mm'\u5206'ss'\u79d2'"},
-            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy-M-d H:mm:ss"},
-            {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy-M-d ah:mm"},
+            {FormatStyle.FULL, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE zzzz ah:mm:ss"},
+            {FormatStyle.LONG, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 z ah:mm:ss"},
+            {FormatStyle.MEDIUM, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 ah:mm:ss"},
+            {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d ah:mm"},
             {FormatStyle.FULL, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE"},
             {FormatStyle.LONG, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"},
-            {FormatStyle.MEDIUM, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy-M-d"},
-            {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy-M-d"},
-            {null, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "ahh'\u65f6'mm'\u5206'ss'\u79d2' z"},
-            {null, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "ahh'\u65f6'mm'\u5206'ss'\u79d2'"},
-            {null, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "H:mm:ss"},
+            {FormatStyle.MEDIUM, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"},
+            {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d"},
+            {null, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "zzzz ah:mm:ss"},
+            {null, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "z ah:mm:ss"},
+            {null, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm:ss"},
             {null, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm"},
         };
     }
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
index aebccfd..7628eeb 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
@@ -94,13 +94,14 @@
             {DAY_OF_WEEK, 6, TextStyle.SHORT, enUS, "Sat"},
             {DAY_OF_WEEK, 7, TextStyle.SHORT, enUS, "Sun"},
 
-            {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "Seg"},
-            {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "Ter"},
-            {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "Qua"},
-            {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "Qui"},
-            {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "Sex"},
-            {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "S\u00E1b"},
-            {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "Dom"},
+            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower
+            {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "seg"},
+            {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "ter"},
+            {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "qua"},
+            {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "qui"},
+            {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "sex"},
+            {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "s\u00E1b"},
+            {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "dom"},
 
             {DAY_OF_WEEK, 1, TextStyle.FULL, enUS, "Monday"},
             {DAY_OF_WEEK, 2, TextStyle.FULL, enUS, "Tuesday"},
@@ -110,13 +111,14 @@
             {DAY_OF_WEEK, 6, TextStyle.FULL, enUS, "Saturday"},
             {DAY_OF_WEEK, 7, TextStyle.FULL, enUS, "Sunday"},
 
-            {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "Segunda-feira"},
-            {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "Ter\u00E7a-feira"},
-            {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "Quarta-feira"},
-            {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "Quinta-feira"},
-            {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "Sexta-feira"},
-            {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "S\u00E1bado"},
-            {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "Domingo"},
+            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower
+            {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "segunda-feira"},
+            {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "ter\u00E7a-feira"},
+            {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "quarta-feira"},
+            {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "quinta-feira"},
+            {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "sexta-feira"},
+            {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "s\u00E1bado"},
+            {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "domingo"},
 
             {MONTH_OF_YEAR, 1, TextStyle.SHORT, enUS, "Jan"},
             {MONTH_OF_YEAR, 2, TextStyle.SHORT, enUS, "Feb"},
@@ -157,18 +159,19 @@
             {MONTH_OF_YEAR, 11, TextStyle.FULL, enUS, "November"},
             {MONTH_OF_YEAR, 12, TextStyle.FULL, enUS, "December"},
 
-            {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "Janeiro"},
-            {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "Fevereiro"},
-            {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "Mar\u00E7o"},
-            {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "Abril"},
-            {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "Maio"},
-            {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "Junho"},
-            {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "Julho"},
-            {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "Agosto"},
-            {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "Setembro"},
-            {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "Outubro"},
-            {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "Novembro"},
-            {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "Dezembro"},
+            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower
+            {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "janeiro"},
+            {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "fevereiro"},
+            {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "mar\u00E7o"},
+            {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "abril"},
+            {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "maio"},
+            {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "junho"},
+            {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "julho"},
+            {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "agosto"},
+            {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "setembro"},
+            {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "outubro"},
+            {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "novembro"},
+            {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "dezembro"},
 
             {AMPM_OF_DAY, 0, TextStyle.SHORT, enUS, "AM"},
             {AMPM_OF_DAY, 1, TextStyle.SHORT, enUS, "PM"},
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestNonIsoFormatter.java b/ojluni/src/test/java/time/test/java/time/format/TestNonIsoFormatter.java
index 6747cdc..6609f2c 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestNonIsoFormatter.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestNonIsoFormatter.java
@@ -76,20 +76,25 @@
         return new Object[][] {
             // Chronology, Format Locale, Numbering Locale, ChronoLocalDate, expected string
             { JAPANESE, Locale.JAPANESE, Locale.JAPANESE, JAPANESE.date(IsoDate),
-              "\u5e73\u621025\u5e742\u670811\u65e5" }, // Japanese Heisei 25-02-11
+              "\u5e73\u621025\u5e742\u670811\u65e5\u6708\u66dc\u65e5" }, // Japanese Heisei 25-02-11
+            // Android-changed: requesting arabic numbering actually produces arabic digits. Also
+            // new CLDR patterns include the era. Test Arabic locale with ASCII digits below.
             { HIJRAH, ARABIC, ARABIC, HIJRAH.date(IsoDate),
+              "\u0627\u0644\u0627\u062b\u0646\u064a\u0646\u060c \u0661 \u0631\u0628\u064a\u0639 "
+              + "\u0627\u0644\u0622\u062e\u0631\u060c \u0661\u0664\u0663\u0664 \u0647\u0640" }, // Hijrah AH 1434-04-01 (Mon)
+            { HIJRAH, ARABIC, Locale.ENGLISH, HIJRAH.date(IsoDate),
               "\u0627\u0644\u0627\u062b\u0646\u064a\u0646\u060c 1 \u0631\u0628\u064a\u0639 "
-              + "\u0627\u0644\u0622\u062e\u0631 1434" }, // Hijrah AH 1434-04-01 (Mon)
+              + "\u0627\u0644\u0622\u062e\u0631\u060c 1434 \u0647\u0640" }, // Hijrah AH 1434-04-01 (Mon)
             { MINGUO, Locale.TAIWAN, Locale.TAIWAN, MINGUO.date(IsoDate),
-              "\u6c11\u570b102\u5e742\u670811\u65e5\u661f\u671f\u4e00" }, // Minguo ROC 102-02-11 (Mon)
+              "\u6c11\u570b102\u5e742\u670811\u65e5 \u661f\u671f\u4e00" }, // Minguo ROC 102-02-11 (Mon)
             { BUDDHIST, thTH, thTH, BUDDHIST.date(IsoDate),
-              "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48"
-              + " 11 \u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c"
-              + " \u0e1e.\u0e28. 2556" }, // ThaiBuddhist BE 2556-02-11
+              "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48 "
+              + "11 \u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c "
+              + "\u0e1e.\u0e28. 2556" }, // ThaiBuddhist BE 2556-02-11
             { BUDDHIST, thTH, thTHTH, BUDDHIST.date(IsoDate),
               "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48 \u0e51\u0e51 "
-              + "\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c \u0e1e.\u0e28. "
-              + "\u0e52\u0e55\u0e55\u0e56" }, // ThaiBuddhist BE 2556-02-11 (with Thai digits)
+              + "\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c "
+              + "\u0e1e.\u0e28. \u0e52\u0e55\u0e55\u0e56" }, // ThaiBuddhist BE 2556-02-11 (with Thai digits)
         };
     }
 
@@ -108,23 +113,24 @@
     Object[][] chronoNamesData() {
         return new Object[][] {
             // Chronology, Locale, Chronology Name
-            { ISO8601,  Locale.ENGLISH, "ISO" },    // No data in CLDR; Use Id.
+            // Android-changed: CLDR data has changed.
+            { ISO8601,  Locale.ENGLISH, "ISO-8601 Calendar" },
             { BUDDHIST, Locale.ENGLISH, "Buddhist Calendar" },
-            { HIJRAH,   Locale.ENGLISH, "Islamic Umm al-Qura Calendar" }, // JDK-8015986
+            { HIJRAH,   Locale.ENGLISH, "Islamic Calendar (Umm al-Qura)" },
             { JAPANESE, Locale.ENGLISH, "Japanese Calendar" },
             { MINGUO,   Locale.ENGLISH, "Minguo Calendar" },
 
-            { ISO8601,  Locale.JAPANESE, "ISO" },    // No data in CLDR; Use Id.
+            { ISO8601,  Locale.JAPANESE, "ISO-8601" },
             { JAPANESE, Locale.JAPANESE, "\u548c\u66a6" },
-            { BUDDHIST, Locale.JAPANESE, "\u30bf\u30a4\u4ecf\u6559\u66a6" },
+            { BUDDHIST, Locale.JAPANESE, "\u4ecf\u66a6" },
 
-            { ISO8601,  thTH, "ISO" },    // No data in CLDR; Use Id.
+            { ISO8601,  thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19 ISO-8601" },
             { JAPANESE, thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e0d\u0e35\u0e48\u0e1b\u0e38\u0e48\u0e19" },
             { BUDDHIST, thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e1e\u0e38\u0e17\u0e18" },
 
-            { HIJRAH,   ARABIC, "\u0644\u062a\u0642\u0648\u064a\u0645 "
-                                + "\u0627\u0644\u0647\u062c\u0631\u064a\u060c "
-                                + "\u0623\u0645 \u0627\u0644\u0642\u0631\u0649" }, // JDK-8015986
+            { HIJRAH,   ARABIC, "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 "
+                                + "\u0627\u0644\u0625\u0633\u0644\u0627\u0645\u064a "
+                                + "(\u0623\u0645 \u0627\u0644\u0642\u0631\u0649)" }, // JDK-8015986
         };
     }
 
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestTextParser.java b/ojluni/src/test/java/time/test/java/time/format/TestTextParser.java
index 07bd214..721f337 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestTextParser.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestTextParser.java
@@ -208,10 +208,11 @@
     Object[][] providerStandaloneText() {
         // Locale, TemporalField, TextStyle, expected value, input text
         return new Object[][] {
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,   1, "\u042f\u043d\u0432\u0430\u0440\u044c"},
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,  12, "\u0414\u0435\u043a\u0430\u0431\u0440\u044c"},
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE,  1, "\u042f\u043d\u0432."},
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 12, "\u0414\u0435\u043a."},
+            // Android-changed: CLDR provides russian days/months in lower-case and with a fullstop.
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,   1, "\u044f\u043d\u0432\u0430\u0440\u044c" },
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,  12, "\u0434\u0435\u043a\u0430\u0431\u0440\u044c" },
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE,  1, "\u044f\u043d\u0432." },
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 12, "\u0434\u0435\u043a." },
             {FINNISH, DAY_OF_WEEK,   TextStyle.FULL_STANDALONE,   2, "tiistai"},
             {FINNISH, DAY_OF_WEEK,   TextStyle.SHORT_STANDALONE,  2, "ti"},
         };
@@ -236,10 +237,11 @@
     Object[][] providerLenientText() {
         // Locale, TemporalField, expected value, input text
         return new Object[][] {
-            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044f"}, // full format
-            {RUSSIAN, MONTH_OF_YEAR, 1, "\u042f\u043d\u0432\u0430\u0440\u044c"}, // full standalone
-            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432"},  // short format
-            {RUSSIAN, MONTH_OF_YEAR, 1, "\u042f\u043d\u0432."}, // short standalone
+            // Android-changed: CLDR provides russian months in lower-case and with a fullstop.
+            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044f" }, // full format
+            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044c" }, // full standalone
+            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432." },  // short format
+            {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432." }, // short standalone
         };
     }
 
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestTextPrinter.java b/ojluni/src/test/java/time/test/java/time/format/TestTextPrinter.java
index 662288c..19e6421 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestTextPrinter.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestTextPrinter.java
@@ -235,8 +235,9 @@
         return new Object[][] {
             // standalone names for 2013-01-01 (Tue)
             // Locale, TemporalField, TextStyle, expected text
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,  "\u042f\u043d\u0432\u0430\u0440\u044c"},
-            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, "\u042f\u043d\u0432."},
+            // Android-changed: CLDR uses lower case for russian month names.
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE,  "\u044f\u043d\u0432\u0430\u0440\u044c"},
+            {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, "\u044f\u043d\u0432."},
             {FINNISH, DAY_OF_WEEK,   TextStyle.FULL_STANDALONE,  "tiistai"},
             {FINNISH, DAY_OF_WEEK,   TextStyle.SHORT_STANDALONE, "ti"},
         };
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java b/ojluni/src/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java
index 94b6096..4855740 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java
@@ -46,6 +46,7 @@
 
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
+import android.icu.impl.ZoneMeta;
 
 /*
  * @test
@@ -67,7 +68,8 @@
 
     public void test_printText() {
         Random r = RandomFactory.getRandom();
-        int N = 8;
+        // Android changed: only run one iteration.
+        int N = 1;
         Locale[] locales = Locale.getAvailableLocales();
         Set<String> zids = ZoneRulesProvider.getAvailableZoneIds();
         ZonedDateTime zdt = ZonedDateTime.now();
@@ -76,14 +78,29 @@
         while (N-- > 0) {
             zdt = zdt.withDayOfYear(r.nextInt(365) + 1)
                      .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400));
-            for (String zid : zids) {
-                if (zid.equals("ROC") || zid.startsWith("Etc/GMT")) {
-                    continue;      // TBD: match jdk behavior?
+            // Android-changed: loop over locales first to speed up test. TimeZoneNames are cached
+            // per locale, but the cache only holds the most recently used locales.
+            for (Locale locale : locales) {
+                // Android-changed: "ji" isn't correctly aliased to "yi", see http//b/8634320.
+                if (locale.getLanguage().equals("ji")) {
+                    continue;
                 }
-                zdt = zdt.withZoneSameLocal(ZoneId.of(zid));
-                TimeZone tz = TimeZone.getTimeZone(zid);
-                boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli()));
-                for (Locale locale : locales) {
+                for (String zid : zids) {
+                    if (zid.equals("ROC") || zid.startsWith("Etc/GMT")) {
+                        continue;      // TBD: match jdk behavior?
+                    }
+                    // Android-changed (http://b/33197219): TimeZone.getDisplayName() for
+                    // non-canonical time zones are not correct.
+                    if (!zid.equals(ZoneMeta.getCanonicalCLDRID(zid))) {
+                        continue;
+                    }
+                    zdt = zdt.withZoneSameLocal(ZoneId.of(zid));
+                    TimeZone tz = TimeZone.getTimeZone(zid);
+                    // Android-changed: We don't have long names for GMT.
+                    if (tz.getID().equals("GMT")) {
+                        continue;
+                    }
+                    boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli()));
                     printText(locale, zdt, TextStyle.FULL, tz,
                             tz.getDisplayName(isDST, TimeZone.LONG, locale));
                     printText(locale, zdt, TextStyle.SHORT, tz,
@@ -95,6 +112,10 @@
 
     private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, TimeZone zone, String expected) {
         String result = getFormatter(locale, style).format(zdt);
+        // Android-changed: TimeZone.getDisplayName() will never return "GMT".
+        if (result.startsWith("GMT") && expected.equals("GMT+00:00")) {
+            return;
+        }
         if (!result.equals(expected)) {
             if (result.equals("FooLocation")) { // from rules provider test if same vm
                 return;
@@ -107,6 +128,8 @@
         assertEquals(result, expected);
     }
 
+    // Android-changed: disable test as it doesn't assert anything and produces a lot of output.
+    @Test(enabled = false)
     public void test_ParseText() {
         Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH };
         Set<String> zids = ZoneRulesProvider.getAvailableZoneIds();
diff --git a/ojluni/src/test/java/time/test/java/time/temporal/TestChronoField.java b/ojluni/src/test/java/time/test/java/time/temporal/TestChronoField.java
index 41d464c..4946ccd 100644
--- a/ojluni/src/test/java/time/test/java/time/temporal/TestChronoField.java
+++ b/ojluni/src/test/java/time/test/java/time/temporal/TestChronoField.java
@@ -123,7 +123,8 @@
     public void test_IsoFields_week_based_year() {
         Locale locale = Locale.US;
         String name = IsoFields.WEEK_OF_WEEK_BASED_YEAR.getDisplayName(locale);
-        assertEquals(name, "Week");
+        // Android-changed: week is lower-case in CLDR.
+        assertEquals(name, "week");
     }
 
     @Test(expectedExceptions=NullPointerException.class)
@@ -136,7 +137,8 @@
         Locale locale = Locale.US;
         TemporalField weekOfYearField = WeekFields.SUNDAY_START.weekOfYear();
         String name = weekOfYearField.getDisplayName(locale);
-        assertEquals(name, "Week");
+        // Android-changed: week is lower-case in CLDR.
+        assertEquals(name, "week");
     }
 
     @Test(expectedExceptions=NullPointerException.class)
diff --git a/ojluni/src/test/java/time/test/java/util/TestFormatter.java b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
index 67a73ce..afd5fc4 100644
--- a/ojluni/src/test/java/time/test/java/util/TestFormatter.java
+++ b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
@@ -92,7 +92,8 @@
         Chronology chrono = Chronology.ofLocale(calLocale);
         ChronoLocalDate now = chrono.dateNow();
         ChronoLocalDateTime<?> ldt0 = now.atTime(LocalTime.now());
-        ChronoZonedDateTime<?>  zdt0 = ldt0.atZone(ZoneId.systemDefault());
+        // Android changed: use hard-coded zone id instead of system default.
+        ChronoZonedDateTime<?>  zdt0 = ldt0.atZone(ZoneId.of("America/Los_Angeles"));
         ChronoZonedDateTime<?>[] zdts = new ChronoZonedDateTime<?>[] {
             zdt0,
             zdt0.withZoneSameLocal(ZoneId.of("UTC")),
@@ -105,9 +106,16 @@
                 zdt = zdt.with(ChronoField.DAY_OF_YEAR, (r.nextInt(365) + 1))
                          .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400));
                 Instant instant = zdt.toInstant();
-                Calendar cal = Calendar.getInstance(calLocale);
+                // Android changed: Calendar.getInstance() only returns GregorianCalendar.
+                // Manually get a JapaneseImperialCalendar for the test.
+                TimeZone tz = TimeZone.getTimeZone(zdt.getZone());
+                Calendar cal;
+                if (calLocale.getLanguage().equals("ja")) {
+                    cal = Calendar.getJapanesImperialInstance(tz, calLocale);
+                } else {
+                    cal = Calendar.getInstance(tz, calLocale);
+                }
                 cal.setTimeInMillis(instant.toEpochMilli());
-                cal.setTimeZone(TimeZone.getTimeZone(zdt.getZone()));
                 for (Locale locale : locales) {
                     for (String fmtStr : fmtStrDate) {
                         testDate(fmtStr, locale, zdt, cal);
@@ -197,18 +205,22 @@
     }
 
     private String toZoneIdStr(String expected) {
-        return expected.replaceAll("(?:GMT|UTC)(?<off>[+\\-]?[0-9]{2}:[0-9]{2})", "${off}");
+        // Android changed: java.util.Calendar and java.time types are formatted identically.
+        return expected;
     }
 
     private String toZoneOffsetStr(String expected) {
-        return expected.replaceAll("(?:GMT|UTC)(?<off>[+\\-]?[0-9]{2}:[0-9]{2})", "${off}")
-                       .replaceAll("GMT|UTC|UT", "Z");
+        // Android changed: Android Matcher doesn't support named groups. Also GMT/Z is formatted as
+        // "GMT+00:00".
+        return expected.replaceAll("GMT(?:\\+00:00)|UTC|UT", "Z")
+                .replaceAll("(?:GMT|UTC)([+\\-]?[0-9]{2}:[0-9]{2})", "$1");
     }
 
     private void testZoneId(Locale locale, ChronoZonedDateTime<?> zdt, Calendar cal) {
         String fmtStr = "z:[%tz] z:[%1$Tz] Z:[%1$tZ] Z:[%1$TZ]";
         printFmtStr(locale, fmtStr);
-        String expected = toZoneIdStr(test(fmtStr, locale, null, cal));
+        String calOutput = test(fmtStr, locale, null, cal);
+        String expected = toZoneIdStr(calOutput);
         test(fmtStr, locale, expected, zdt);
         // get a new cal with fixed tz
         Calendar cal0 = Calendar.getInstance();
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 6907dde..a64b131 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1409,7 +1409,6 @@
     ojluni/src/main/java/sun/net/ftp/FtpReplyCode.java \
     ojluni/src/main/java/sun/net/ftp/impl/DefaultFtpClientProvider.java \
     ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java \
-    ojluni/src/main/java/sun/net/InetAddressCachePolicy.java \
     ojluni/src/main/java/sun/net/NetHooks.java \
     ojluni/src/main/java/sun/net/NetProperties.java \
     ojluni/src/main/java/sun/net/NetworkClient.java \
@@ -1418,10 +1417,7 @@
     ojluni/src/main/java/sun/net/ProgressMeteringPolicy.java \
     ojluni/src/main/java/sun/net/ProgressMonitor.java \
     ojluni/src/main/java/sun/net/ProgressSource.java \
-    ojluni/src/main/java/sun/net/RegisteredDomain.java \
     ojluni/src/main/java/sun/net/ResourceManager.java \
-    ojluni/src/main/java/sun/net/smtp/SmtpClient.java \
-    ojluni/src/main/java/sun/net/smtp/SmtpProtocolException.java \
     ojluni/src/main/java/sun/net/SocksProxy.java \
     ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java \
     ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java \
@@ -1429,10 +1425,8 @@
     ojluni/src/main/java/sun/net/TelnetInputStream.java \
     ojluni/src/main/java/sun/net/TelnetOutputStream.java \
     ojluni/src/main/java/sun/net/TelnetProtocolException.java \
-    ojluni/src/main/java/sun/net/TransferProtocolClient.java \
     ojluni/src/main/java/sun/net/util/IPAddressUtil.java \
     ojluni/src/main/java/sun/net/util/URLUtil.java \
-    ojluni/src/main/java/sun/net/www/HeaderParser.java \
     ojluni/src/main/java/sun/net/www/MessageHeader.java \
     ojluni/src/main/java/sun/net/www/MeteredStream.java \
     ojluni/src/main/java/sun/net/www/ParseUtil.java \
@@ -1445,7 +1439,6 @@
     ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java \
     ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java \
     ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java \
-    ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java \
     ojluni/src/main/java/sun/nio/ByteBuffered.java \
     ojluni/src/main/java/sun/nio/ch/AbstractPollArrayWrapper.java \
     ojluni/src/main/java/sun/nio/ch/AbstractPollSelectorImpl.java \
diff --git a/tzdata/tools2/src/main/libcore/tzdata/update2/tools/CreateTimeZoneBundle.java b/tzdata/tools2/src/main/libcore/tzdata/update2/tools/CreateTimeZoneBundle.java
index 6297663..4013326 100644
--- a/tzdata/tools2/src/main/libcore/tzdata/update2/tools/CreateTimeZoneBundle.java
+++ b/tzdata/tools2/src/main/libcore/tzdata/update2/tools/CreateTimeZoneBundle.java
@@ -23,6 +23,7 @@
 import java.io.OutputStream;
 import java.io.Reader;
 import java.util.Properties;
+import libcore.tzdata.update2.BundleVersion;
 import libcore.tzdata.update2.TimeZoneBundle;
 
 /**
@@ -48,9 +49,13 @@
             System.exit(2);
         }
         Properties p = loadProperties(f);
+        BundleVersion bundleVersion = new BundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION,
+                getMandatoryProperty(p, "rules.version"),
+                Integer.parseInt(getMandatoryProperty(p, "revision")));
         TimeZoneBundleBuilder builder = new TimeZoneBundleBuilder()
-                .setRulesVersion(getMandatoryProperty(p, "rules.version"))
-                .setAndroidRevision(getMandatoryProperty(p, "android.revision"))
+                .setBundleVersion(bundleVersion)
                 .setTzData(getMandatoryPropertyFile(p, "bionic.file"))
                 .setIcuData(getMandatoryPropertyFile(p, "icu.file"));
 
diff --git a/tzdata/tools2/src/main/libcore/tzdata/update2/tools/TimeZoneBundleBuilder.java b/tzdata/tools2/src/main/libcore/tzdata/update2/tools/TimeZoneBundleBuilder.java
index 39aa496..3f7c323 100644
--- a/tzdata/tools2/src/main/libcore/tzdata/update2/tools/TimeZoneBundleBuilder.java
+++ b/tzdata/tools2/src/main/libcore/tzdata/update2/tools/TimeZoneBundleBuilder.java
@@ -31,31 +31,28 @@
  */
 public final class TimeZoneBundleBuilder {
 
-    private String bundleFormatVersion = BundleVersion.FULL_BUNDLE_FORMAT_VERSION;
-    private String rulesVersion;
-    private String androidRevision;
+    private BundleVersion bundleVersion;
     private byte[] tzData;
     private byte[] icuData;
 
-    // For use in tests.
-    public TimeZoneBundleBuilder setBundleVersionForTests(String bundleVersion) {
-        this.bundleFormatVersion = bundleVersion;
-        return this;
-    }
-
-    public TimeZoneBundleBuilder setRulesVersion(String rulesVersion) {
-        this.rulesVersion = rulesVersion;
-        return this;
-    }
-
-    public TimeZoneBundleBuilder setAndroidRevision(String androidRevision) {
-        this.androidRevision = androidRevision;
+    public TimeZoneBundleBuilder setBundleVersion(BundleVersion bundleVersion) {
+        this.bundleVersion = bundleVersion;
         return this;
     }
 
     public TimeZoneBundleBuilder clearVersionForTests() {
         // This has the effect of omitting the version file in buildUnvalidated().
-        this.bundleFormatVersion = null;
+        this.bundleVersion = null;
+        return this;
+    }
+
+    public TimeZoneBundleBuilder replaceFormatVersionForTests(int majorVersion, int minorVersion) {
+        try {
+            bundleVersion = new BundleVersion(
+                    majorVersion, minorVersion, bundleVersion.rulesVersion, bundleVersion.revision);
+        } catch (BundleException e) {
+            throw new IllegalArgumentException();
+        }
         return this;
     }
 
@@ -95,10 +92,8 @@
     public TimeZoneBundle buildUnvalidated() throws BundleException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try (ZipOutputStream zos = new ZipOutputStream(baos)) {
-            if (bundleFormatVersion != null && rulesVersion != null && androidRevision != null) {
-                BundleVersion bundleVersion =
-                        new BundleVersion(bundleFormatVersion, rulesVersion, androidRevision);
-                addZipEntry(zos, TimeZoneBundle.BUNDLE_VERSION_FILE_NAME, bundleVersion.getBytes());
+            if (bundleVersion != null) {
+                addZipEntry(zos, TimeZoneBundle.BUNDLE_VERSION_FILE_NAME, bundleVersion.toBytes());
             }
 
             if (tzData != null) {
@@ -117,26 +112,9 @@
      * Builds a {@link TimeZoneBundle}.
      */
     public TimeZoneBundle build() throws BundleException {
-        if (bundleFormatVersion == null) {
+        if (bundleVersion == null) {
             throw new IllegalStateException("Missing bundleVersion");
         }
-        if (!BundleVersion.BUNDLE_FORMAT_VERSION_PATTERN.matcher(bundleFormatVersion).matches()) {
-            throw new IllegalStateException("bundleVersion invalid: " + bundleFormatVersion);
-        }
-
-        if (rulesVersion == null) {
-            throw new IllegalStateException("Missing rulesVersion");
-        }
-        if (!BundleVersion.RULES_VERSION_PATTERN.matcher(rulesVersion).matches()) {
-            throw new IllegalStateException("rulesVersion invalid: " + rulesVersion);
-        }
-
-        if (androidRevision == null) {
-            throw new IllegalStateException("Missing androidRevision");
-        }
-        if (!BundleVersion.ANDROID_REVISION_PATTERN.matcher(androidRevision).matches()) {
-            throw new IllegalStateException("androidRevision invalid: " + androidRevision);
-        }
         if (icuData == null) {
             throw new IllegalStateException("Missing icuData");
         }
diff --git a/tzdata/tools2/testing/prepareTzDataUpdates.sh b/tzdata/tools2/testing/prepareTzDataUpdates.sh
index 99cd60f..b467199 100755
--- a/tzdata/tools2/testing/prepareTzDataUpdates.sh
+++ b/tzdata/tools2/testing/prepareTzDataUpdates.sh
@@ -84,7 +84,7 @@
 
 TZ_PREVIOUS_UPDATE_PROPERTIES=${TMP}/tzupdate.properties.${TZ_PREVIOUS}
 cat > ${TZ_PREVIOUS_UPDATE_PROPERTIES} <<EOF
-android.revision=001
+revision=1
 rules.version=${TZ_PREVIOUS}
 bionic.file=${TMP_PREVIOUS}/tzdata
 icu.file=${TMP_PREVIOUS}/icu_tzdata.dat
@@ -113,7 +113,7 @@
 
 TZ_CURRENT_UPDATE_PROPERTIES=${TMP}/tzupdate.properties.${TZ_CURRENT}
 cat > ${TZ_CURRENT_UPDATE_PROPERTIES} <<EOF
-android.revision=001
+revision=1
 rules.version=${TZ_CURRENT}
 bionic.file=${TMP_CURRENT}/tzdata
 icu.file=${TMP_CURRENT}/icu_tzdata.dat
@@ -142,7 +142,7 @@
 
 TZ_NEXT_UPDATE_PROPERTIES=${TMP}/tzupdate.properties.${TZ_NEXT}
 cat > ${TZ_NEXT_UPDATE_PROPERTIES} <<EOF
-android.revision=001
+revision=1
 rules.version=${TZ_NEXT}
 bionic.file=${TMP_NEXT}/tzdata
 icu.file=${TMP_NEXT}/icu_tzdata.dat
diff --git a/tzdata/tools2/tzupdate.properties b/tzdata/tools2/tzupdate.properties
index f46d942..82fa2c4 100644
--- a/tzdata/tools2/tzupdate.properties
+++ b/tzdata/tools2/tzupdate.properties
@@ -3,8 +3,8 @@
 # This should be the tzdata version. e.g. "2015a".
 rules.version=
 
-# This is used to indicate when Android has issued a revision. e.g. "001", "002".
-android.revision=001
+# This is used to indicate when Android has issued a revision. e.g. "1", "2".
+revision=1
 
 bionic.file=
 icu.file=
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
index 6a366da..1889f18 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
@@ -17,103 +17,116 @@
 package libcore.tzdata.update2;
 
 import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
- * Constants and logic associated with the timezone bundle version file.
+ * Constants and logic associated with the time zone bundle version file.
  */
 public class BundleVersion {
 
     /**
-     * The current bundle format version in the form XXX.YYY. Increment the first number (XXX)
-     * when making incompatible changes to the bundle structure, or the files contained within.
-     * The second number (YYY) is currently ignored.
+     * The major bundle format version supported by this device.
+     * Increment this for non-backwards compatible changes to the bundle format.
      */
-    public static final String BUNDLE_FORMAT_MAJOR_VERSION = "001";
+    public static final int CURRENT_FORMAT_MAJOR_VERSION = 1;
 
-    public static final String FULL_BUNDLE_FORMAT_VERSION = BUNDLE_FORMAT_MAJOR_VERSION + ".001";
+    /**
+     * The minor bundle format version supported by this device. Increment this for
+     * backwards-compatible changes to the bundle format.
+     */
+    public static final int CURRENT_FORMAT_MINOR_VERSION = 1;
 
-    private static final int BUNDLE_FORMAT_LENGTH = 7;
+    /** The full major + minor bundle format version for this device. */
+    private static final String FULL_CURRENT_FORMAT_VERSION_STRING =
+            toFormatVersionString(CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION);
 
-    public static final Pattern BUNDLE_FORMAT_VERSION_PATTERN = Pattern.compile("\\d{3}\\.\\d{3}");
+    private static final int FORMAT_VERSION_STRING_LENGTH =
+            FULL_CURRENT_FORMAT_VERSION_STRING.length();
+    private static final Pattern FORMAT_VERSION_PATTERN = Pattern.compile("(\\d{3})\\.(\\d{3})");
 
     /** A pattern that matches the IANA rules value of a rules update. e.g. "2016g" */
-    public static final Pattern RULES_VERSION_PATTERN = Pattern.compile("\\d{4}\\w");
+    private static final Pattern RULES_VERSION_PATTERN = Pattern.compile("(\\d{4}\\w)");
 
     private static final int RULES_VERSION_LENGTH = 5;
 
-    /** A pattern that matches the Android revision of a rules update. e.g. "001" */
-    public static final Pattern ANDROID_REVISION_PATTERN = Pattern.compile("\\d{3}");
+    /** A pattern that matches the revision of a rules update. e.g. "001" */
+    private static final Pattern REVISION_PATTERN = Pattern.compile("(\\d{3})");
 
-    private static final int ANDROID_REVISION_LENGTH = 3;
+    private static final int REVISION_LENGTH = 3;
 
     /**
      * The length of a well-formed bundle version file:
-     * {Bundle version}|{Rule version}|{Android revision}
+     * {Bundle version}|{Rule version}|{Revision}
      */
-    public static final int BUNDLE_VERSION_FILE_LENGTH = BUNDLE_FORMAT_LENGTH + 1
+    static final int BUNDLE_VERSION_FILE_LENGTH = FORMAT_VERSION_STRING_LENGTH + 1
             + RULES_VERSION_LENGTH
-            + 1 + ANDROID_REVISION_LENGTH;
+            + 1 + REVISION_LENGTH;
 
     private static final Pattern BUNDLE_VERSION_PATTERN = Pattern.compile(
-            BUNDLE_FORMAT_VERSION_PATTERN.pattern() + "\\|"
+            FORMAT_VERSION_PATTERN.pattern() + "\\|"
                     + RULES_VERSION_PATTERN.pattern() + "\\|"
-                    + ANDROID_REVISION_PATTERN.pattern()
+                    + REVISION_PATTERN.pattern()
                     + ".*" /* ignore trailing */);
 
-    private final String bundleFormatVersion;
-
+    public final int formatMajorVersion;
+    public final int formatMinorVersion;
     public final String rulesVersion;
+    public final int revision;
 
-    public final String androidRevision;
-
-    public BundleVersion(String bundleFormatVersion, String rulesVersion,
-            String androidRevision) throws BundleException {
-        if (!BUNDLE_FORMAT_VERSION_PATTERN.matcher(bundleFormatVersion).matches()) {
-            throw new BundleException("Invalid bundleFormatVersion: " + bundleFormatVersion);
-        }
+    public BundleVersion(int formatMajorVersion, int formatMinorVersion, String rulesVersion,
+            int revision) throws BundleException {
+        this.formatMajorVersion = validate3DigitVersion(formatMajorVersion);
+        this.formatMinorVersion = validate3DigitVersion(formatMinorVersion);
         if (!RULES_VERSION_PATTERN.matcher(rulesVersion).matches()) {
             throw new BundleException("Invalid rulesVersion: " + rulesVersion);
         }
-        if (!ANDROID_REVISION_PATTERN.matcher(androidRevision).matches()) {
-            throw new BundleException("Invalid androidRevision: " + androidRevision);
-        }
-        this.bundleFormatVersion = bundleFormatVersion;
         this.rulesVersion = rulesVersion;
-        this.androidRevision = androidRevision;
+        this.revision = validate3DigitVersion(revision);
     }
 
-    public static BundleVersion extractFromBytes(byte[] bytes) throws BundleException {
+    public static BundleVersion fromBytes(byte[] bytes) throws BundleException {
         String bundleVersion = new String(bytes, StandardCharsets.US_ASCII);
         try {
-            if (!BUNDLE_VERSION_PATTERN.matcher(bundleVersion).matches()) {
+            Matcher matcher = BUNDLE_VERSION_PATTERN.matcher(bundleVersion);
+            if (!matcher.matches()) {
                 throw new BundleException("Invalid bundle version string: " + bundleVersion);
             }
-            String bundleFormatVersion = bundleVersion.substring(0, 7);
-            String rulesVersion = bundleVersion.substring(8, 13);
-            String androidRevision = bundleVersion.substring(14);
-            return new BundleVersion(bundleFormatVersion, rulesVersion, androidRevision);
+            String formatMajorVersion = matcher.group(1);
+            String formatMinorVersion = matcher.group(2);
+            String rulesVersion = matcher.group(3);
+            String revision = matcher.group(4);
+            return new BundleVersion(
+                    from3DigitVersionString(formatMajorVersion),
+                    from3DigitVersionString(formatMinorVersion),
+                    rulesVersion,
+                    from3DigitVersionString(revision));
         } catch (IndexOutOfBoundsException e) {
             // The use of the regexp above should make this impossible.
             throw new BundleException("Bundle version string too short:" + bundleVersion);
         }
     }
 
-    public String getBundleFormatMajorVersion() {
-        return bundleFormatVersion.substring(0, 3);
-    }
-
-    public byte[] getBytes() {
-        return getBytes(bundleFormatVersion, rulesVersion, androidRevision);
+    public byte[] toBytes() {
+        return toBytes(formatMajorVersion, formatMinorVersion, rulesVersion, revision);
     }
 
     // @VisibleForTesting - can be used to construct invalid bundle version bytes.
-    public static byte[] getBytes(
-            String bundleFormatVersion, String rulesVersion, String androidRevision) {
-        return (bundleFormatVersion + "|" + rulesVersion + "|" + androidRevision)
+    public static byte[] toBytes(
+            int majorFormatVersion, int minorFormatVerison, String rulesVersion, int revision) {
+        return (toFormatVersionString(majorFormatVersion, minorFormatVerison)
+                + "|" + rulesVersion + "|" + to3DigitVersionString(revision))
                 .getBytes(StandardCharsets.US_ASCII);
     }
 
+    public static boolean isCompatibleWithThisDevice(BundleVersion bundleVersion) {
+        return (BundleVersion.CURRENT_FORMAT_MAJOR_VERSION
+                == bundleVersion.formatMajorVersion)
+                && (BundleVersion.CURRENT_FORMAT_MINOR_VERSION
+                <= bundleVersion.formatMinorVersion);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -125,21 +138,65 @@
 
         BundleVersion that = (BundleVersion) o;
 
-        if (!bundleFormatVersion.equals(that.bundleFormatVersion)) {
+        if (formatMajorVersion != that.formatMajorVersion) {
             return false;
         }
-        if (!rulesVersion.equals(that.rulesVersion)) {
+        if (formatMinorVersion != that.formatMinorVersion) {
             return false;
         }
-        return androidRevision.equals(that.androidRevision);
+        if (revision != that.revision) {
+            return false;
+        }
+        return rulesVersion.equals(that.rulesVersion);
     }
 
     @Override
     public String toString() {
         return "BundleVersion{" +
-                "bundleFormatVersion='" + bundleFormatVersion + '\'' +
+                "formatMajorVersion=" + formatMajorVersion +
+                ", formatMinorVersion=" + formatMinorVersion +
                 ", rulesVersion='" + rulesVersion + '\'' +
-                ", androidRevision='" + androidRevision + '\'' +
+                ", revision=" + revision +
                 '}';
     }
+
+    /**
+     * Returns a version as a zero-padded three-digit String value.
+     */
+    private static String to3DigitVersionString(int version) {
+        try {
+            return String.format(Locale.ROOT, "%03d", validate3DigitVersion(version));
+        } catch (BundleException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * Validates and parses a zero-padded three-digit String value.
+     */
+    private static int from3DigitVersionString(String versionString) throws BundleException {
+        final String parseErrorMessage = "versionString must be a zero padded, 3 digit, positive"
+                + " decimal integer";
+        if (versionString.length() != 3) {
+            throw new BundleException(parseErrorMessage);
+        }
+        try {
+            int version = Integer.parseInt(versionString);
+            return validate3DigitVersion(version);
+        } catch (NumberFormatException e) {
+            throw new BundleException(parseErrorMessage, e);
+        }
+    }
+
+    private static int validate3DigitVersion(int value) throws BundleException {
+        if (value < 1 || value > 999) {
+            throw new BundleException("Expected 1 <= value <= 999, was " + value);
+        }
+        return value;
+    }
+
+    private static String toFormatVersionString(int majorFormatVersion, int minorFormatVersion) {
+        return to3DigitVersionString(majorFormatVersion)
+                + "." + to3DigitVersionString(minorFormatVersion);
+    }
 }
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundle.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundle.java
index 6d11469..f517b5a 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundle.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundle.java
@@ -26,7 +26,7 @@
 import java.util.zip.ZipInputStream;
 
 /**
- * A timezone bundle. This is a thin wrapper around some in-memory bytes representing a zip
+ * A time zone bundle. This is a thin wrapper around some in-memory bytes representing a zip
  * archive and logic for its safe extraction.
  */
 public final class TimeZoneBundle {
@@ -67,7 +67,7 @@
         if (contents == null) {
             throw new BundleException("Bundle version file entry not found");
         }
-        return BundleVersion.extractFromBytes(contents);
+        return BundleVersion.fromBytes(contents);
     }
 
     private static byte[] getEntryContents(InputStream is, String entryName) throws IOException {
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
index 601b8e2..c2ad47e 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
@@ -27,6 +27,16 @@
  * testing. This class is not thread-safe: callers are expected to handle mutual exclusion.
  */
 public final class TimeZoneBundleInstaller {
+    /** {@link #installWithErrorCode(byte[])} result code: Success. */
+    public final static int INSTALL_SUCCESS = 0;
+    /** {@link #installWithErrorCode(byte[])} result code: Bundle corrupt. */
+    public final static int INSTALL_FAIL_BAD_BUNDLE_STRUCTURE = 1;
+    /** {@link #installWithErrorCode(byte[])} result code: Bundle version incompatible. */
+    public final static int INSTALL_FAIL_BAD_BUNDLE_FORMAT_VERSION = 2;
+    /** {@link #installWithErrorCode(byte[])} result code: Bundle rules too old for device. */
+    public final static int INSTALL_FAIL_RULES_TOO_OLD = 3;
+    /** {@link #installWithErrorCode(byte[])} result code: Bundle content failed validation. */
+    public final static int INSTALL_FAIL_VALIDATION_ERROR = 4;
 
     private static final String CURRENT_TZ_DATA_DIR_NAME = "current";
     private static final String WORKING_DIR_NAME = "working";
@@ -69,6 +79,17 @@
      * If the installation completed successfully this method returns {@code true}.
      */
     public boolean install(byte[] content) throws IOException {
+        int result = installWithErrorCode(content);
+        return result == INSTALL_SUCCESS;
+    }
+
+    /**
+     * Install the supplied time zone bundle.
+     *
+     * <p>Errors during unpacking or installation will throw an {@link IOException}.
+     * Returns {@link #INSTALL_SUCCESS} or an error code.
+     */
+    public int installWithErrorCode(byte[] content) throws IOException {
         if (oldTzDataDir.exists()) {
             FileUtils.deleteRecursive(oldTzDataDir);
         }
@@ -84,39 +105,39 @@
                 bundleVersion = readBundleVersion(workingDir);
             } catch (BundleException e) {
                 Slog.i(logTag, "Invalid bundle version: " + e.getMessage());
-                return false;
+                return INSTALL_FAIL_BAD_BUNDLE_STRUCTURE;
             }
             if (bundleVersion == null) {
                 Slog.i(logTag, "Update not applied: Bundle version could not be loaded");
-                return false;
+                return INSTALL_FAIL_BAD_BUNDLE_STRUCTURE;
             }
-            if (!checkBundleFormatVersion(bundleVersion)) {
+            if (!BundleVersion.isCompatibleWithThisDevice(bundleVersion)) {
                 Slog.i(logTag, "Update not applied: Bundle format version check failed: "
                         + bundleVersion);
-                return false;
+                return INSTALL_FAIL_BAD_BUNDLE_FORMAT_VERSION;
             }
 
             if (!checkBundleDataFilesExist(workingDir)) {
                 Slog.i(logTag, "Update not applied: Bundle is missing required data file(s)");
-                return false;
+                return INSTALL_FAIL_BAD_BUNDLE_STRUCTURE;
             }
 
             if (!checkBundleRulesNewerThanSystem(systemTzDataFile, bundleVersion)) {
                 Slog.i(logTag, "Update not applied: Bundle rules version check failed");
-                return false;
+                return INSTALL_FAIL_RULES_TOO_OLD;
             }
 
             File zoneInfoFile = new File(workingDir, TimeZoneBundle.TZDATA_FILE_NAME);
             ZoneInfoDB.TzData tzData = ZoneInfoDB.TzData.loadTzData(zoneInfoFile.getPath());
             if (tzData == null) {
                 Slog.i(logTag, "Update not applied: " + zoneInfoFile + " could not be loaded");
-                return false;
+                return INSTALL_FAIL_VALIDATION_ERROR;
             }
             try {
                 tzData.validate();
             } catch (IOException e) {
                 Slog.i(logTag, "Update not applied: " + zoneInfoFile + " failed validation", e);
-                return false;
+                return INSTALL_FAIL_VALIDATION_ERROR;
             } finally {
                 tzData.close();
             }
@@ -133,7 +154,7 @@
             Slog.i(logTag, "Moving " + workingDir + " to " + currentTzDataDir);
             FileUtils.rename(workingDir, currentTzDataDir);
             Slog.i(logTag, "Update applied: " + currentTzDataDir + " successfully created");
-            return true;
+            return INSTALL_SUCCESS;
         } finally {
             deleteBestEffort(oldTzDataDir);
             deleteBestEffort(workingDir);
@@ -161,16 +182,17 @@
             return false;
         }
 
-        try {
-            Slog.i(logTag, "Moving " + currentTzDataDir + " to " + oldTzDataDir);
-            // Move currentTzDataDir out of the way in one operation so we can't partially delete
-            // the contents, which would leave a partial install.
-            FileUtils.rename(currentTzDataDir, oldTzDataDir);
-            return true;
-        } finally {
-            // Do our best to delete the now uninstalled timezone data.
-            deleteBestEffort(oldTzDataDir);
-        }
+        Slog.i(logTag, "Moving " + currentTzDataDir + " to " + oldTzDataDir);
+        // Move currentTzDataDir out of the way in one operation so we can't partially delete
+        // the contents, which would leave a partial install.
+        FileUtils.rename(currentTzDataDir, oldTzDataDir);
+
+        // Do our best to delete the now uninstalled timezone data.
+        deleteBestEffort(oldTzDataDir);
+
+        Slog.i(logTag, "Time zone update uninstalled.");
+
+        return true;
     }
 
     /**
@@ -199,6 +221,7 @@
 
     private void deleteBestEffort(File dir) {
         if (dir.exists()) {
+            Slog.i(logTag, "Deleting " + dir);
             try {
                 FileUtils.deleteRecursive(dir);
             } catch (IOException e) {
@@ -230,12 +253,7 @@
         }
         byte[] versionBytes =
                 FileUtils.readBytes(bundleVersionFile, BundleVersion.BUNDLE_VERSION_FILE_LENGTH);
-        return BundleVersion.extractFromBytes(versionBytes);
-    }
-
-    private boolean checkBundleFormatVersion(BundleVersion bundleVersion) {
-        return bundleVersion.getBundleFormatMajorVersion()
-                .equals(BundleVersion.BUNDLE_FORMAT_MAJOR_VERSION);
+        return BundleVersion.fromBytes(versionBytes);
     }
 
     /**
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
new file mode 100644
index 0000000..3c2bff8
--- /dev/null
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.tzdata.update2;
+
+import junit.framework.TestCase;
+
+public class BundleVersionTest extends TestCase {
+
+    private static final int INVALID_VERSION_LOW = 0;
+    private static final int VALID_VERSION = 23;
+    private static final int INVALID_VERSION_HIGH = 1000;
+    private static final String VALID_RULES_VERSION = "2016a";
+    private static final String INVALID_RULES_VERSION = "A016a";
+
+    public void testConstructorValidation() throws Exception {
+        checkConstructorThrows(
+                INVALID_VERSION_LOW, VALID_VERSION, VALID_RULES_VERSION, VALID_VERSION);
+        checkConstructorThrows(
+                INVALID_VERSION_HIGH, VALID_VERSION, VALID_RULES_VERSION, VALID_VERSION);
+        checkConstructorThrows(
+                VALID_VERSION, INVALID_VERSION_LOW, VALID_RULES_VERSION, VALID_VERSION);
+        checkConstructorThrows(
+                VALID_VERSION, INVALID_VERSION_HIGH, VALID_RULES_VERSION, VALID_VERSION);
+        checkConstructorThrows(VALID_VERSION, VALID_VERSION, INVALID_RULES_VERSION, VALID_VERSION);
+        checkConstructorThrows(VALID_VERSION, VALID_VERSION, VALID_RULES_VERSION,
+                INVALID_VERSION_LOW);
+        checkConstructorThrows(VALID_VERSION, VALID_VERSION, VALID_RULES_VERSION,
+                INVALID_VERSION_HIGH);
+    }
+
+    private static void checkConstructorThrows(
+            int majorVersion, int minorVersion, String rulesVersion, int revision) {
+        try {
+            new BundleVersion(majorVersion, minorVersion, rulesVersion, revision);
+            fail();
+        } catch (BundleException expected) {}
+    }
+
+    public void testConstructor() throws Exception {
+        BundleVersion bundleVersion = new BundleVersion(1, 2, VALID_RULES_VERSION, 3);
+        assertEquals(1, bundleVersion.formatMajorVersion);
+        assertEquals(2, bundleVersion.formatMinorVersion);
+        assertEquals(VALID_RULES_VERSION, bundleVersion.rulesVersion);
+        assertEquals(3, bundleVersion.revision);
+    }
+
+    public void testToFromBytesRoundTrip() throws Exception {
+        BundleVersion bundleVersion = new BundleVersion(1, 2, VALID_RULES_VERSION, 3);
+        assertEquals(bundleVersion, BundleVersion.fromBytes(bundleVersion.toBytes()));
+    }
+
+    public void testIsCompatibleWithThisDevice() throws Exception {
+        BundleVersion exactMatch = createBundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
+        assertTrue(BundleVersion.isCompatibleWithThisDevice(exactMatch));
+
+        BundleVersion newerMajor = createBundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION + 1,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
+        assertFalse(BundleVersion.isCompatibleWithThisDevice(newerMajor));
+
+        BundleVersion newerMinor = createBundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION + 1);
+        assertTrue(BundleVersion.isCompatibleWithThisDevice(newerMinor));
+
+        if (BundleVersion.CURRENT_FORMAT_MAJOR_VERSION > 1) {
+            BundleVersion olderMajor = createBundleVersion(
+                    BundleVersion.CURRENT_FORMAT_MAJOR_VERSION - 1,
+                    BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
+            assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMajor));
+        }
+
+        if (BundleVersion.CURRENT_FORMAT_MINOR_VERSION > 1) {
+            BundleVersion olderMinor = createBundleVersion(
+                    BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                    BundleVersion.CURRENT_FORMAT_MINOR_VERSION - 1);
+            assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMinor));
+        }
+    }
+
+    private BundleVersion createBundleVersion(int majorFormatVersion, int minorFormatVersion)
+            throws BundleException {
+        return new BundleVersion(majorFormatVersion, minorFormatVersion, VALID_RULES_VERSION, 3);
+    }
+}
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
index 0c7e52b..fc8fa92 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
@@ -91,10 +91,10 @@
         File doesNotExist = new File(testSystemTzDataDir, "doesNotExist");
         TimeZoneBundleInstaller brokenSystemInstaller = new TimeZoneBundleInstaller(
                 "TimeZoneBundleInstallerTest", doesNotExist, testInstallDir);
-        TimeZoneBundle tzData = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
+        TimeZoneBundle tzData = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
 
         try {
-            brokenSystemInstaller.install(tzData.getBytes());
+            brokenSystemInstaller.installWithErrorCode(tzData.getBytes());
             fail();
         } catch (IOException expected) {}
 
@@ -103,9 +103,11 @@
 
     /** Tests the first successful update on a device */
     public void testInstall_successfulFirstUpdate() throws Exception {
-        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
+        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
 
-        assertTrue(installer.install(bundle.getBytes()));
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertBundleInstalled(bundle);
     }
 
@@ -113,8 +115,10 @@
      * Tests we can install an update the same version as is in /system.
      */
     public void testInstall_successfulFirstUpdate_sameVersionAsSystem() throws Exception {
-        TimeZoneBundle bundle = createValidTimeZoneBundle(SYSTEM_RULES_VERSION, "001");
-        assertTrue(installer.install(bundle.getBytes()));
+        TimeZoneBundle bundle = createValidTimeZoneBundle(SYSTEM_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertBundleInstalled(bundle);
     }
 
@@ -122,8 +126,10 @@
      * Tests we cannot install an update older than the version in /system.
      */
     public void testInstall_unsuccessfulFirstUpdate_olderVersionThanSystem() throws Exception {
-        TimeZoneBundle bundle = createValidTimeZoneBundle(OLDER_RULES_VERSION, "001");
-        assertFalse(installer.install(bundle.getBytes()));
+        TimeZoneBundle bundle = createValidTimeZoneBundle(OLDER_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
@@ -131,16 +137,22 @@
      * Tests an update on a device when there is a prior update already applied.
      */
     public void testInstall_successfulFollowOnUpdate_newerVersion() throws Exception {
-        TimeZoneBundle bundle1 = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
-        assertTrue(installer.install(bundle1.getBytes()));
+        TimeZoneBundle bundle1 = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle1.getBytes()));
         assertBundleInstalled(bundle1);
 
-        TimeZoneBundle bundle2 = createValidTimeZoneBundle(NEW_RULES_VERSION, "002");
-        assertTrue(installer.install(bundle2.getBytes()));
+        TimeZoneBundle bundle2 = createValidTimeZoneBundle(NEW_RULES_VERSION, 2);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle2.getBytes()));
         assertBundleInstalled(bundle2);
 
-        TimeZoneBundle bundle3 = createValidTimeZoneBundle(NEWER_RULES_VERSION, "001");
-        assertTrue(installer.install(bundle3.getBytes()));
+        TimeZoneBundle bundle3 = createValidTimeZoneBundle(NEWER_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle3.getBytes()));
         assertBundleInstalled(bundle3);
     }
 
@@ -149,40 +161,52 @@
      * on update is older than in /system.
      */
     public void testInstall_unsuccessfulFollowOnUpdate_olderVersion() throws Exception {
-        TimeZoneBundle bundle1 = createValidTimeZoneBundle(NEW_RULES_VERSION, "002");
-        assertTrue(installer.install(bundle1.getBytes()));
+        TimeZoneBundle bundle1 = createValidTimeZoneBundle(NEW_RULES_VERSION, 2);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle1.getBytes()));
         assertBundleInstalled(bundle1);
 
-        TimeZoneBundle bundle2 = createValidTimeZoneBundle(OLDER_RULES_VERSION, "001");
-        assertFalse(installer.install(bundle2.getBytes()));
+        TimeZoneBundle bundle2 = createValidTimeZoneBundle(OLDER_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+                installer.installWithErrorCode(bundle2.getBytes()));
         assertBundleInstalled(bundle1);
     }
 
     /** Tests that a bundle with a missing file will not update the content. */
     public void testInstall_missingTzDataFile() throws Exception {
-        TimeZoneBundle installedBundle = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
-        assertTrue(installer.install(installedBundle.getBytes()));
+        TimeZoneBundle installedBundle = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(installedBundle.getBytes()));
         assertBundleInstalled(installedBundle);
 
         TimeZoneBundle incompleteBundle =
-                createValidTimeZoneBundleBuilder(NEWER_RULES_VERSION, "001")
+                createValidTimeZoneBundleBuilder(NEWER_RULES_VERSION, 1)
                         .clearTzDataForTests()
                         .buildUnvalidated();
-        assertFalse(installer.install(incompleteBundle.getBytes()));
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(incompleteBundle.getBytes()));
         assertBundleInstalled(installedBundle);
     }
 
     /** Tests that a bundle with a missing file will not update the content. */
     public void testInstall_missingIcuFile() throws Exception {
-        TimeZoneBundle installedBundle = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
-        assertTrue(installer.install(installedBundle.getBytes()));
+        TimeZoneBundle installedBundle = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(installedBundle.getBytes()));
         assertBundleInstalled(installedBundle);
 
         TimeZoneBundle incompleteBundle =
-                createValidTimeZoneBundleBuilder(NEWER_RULES_VERSION, "001")
+                createValidTimeZoneBundleBuilder(NEWER_RULES_VERSION, 1)
                         .clearIcuDataForTests()
                         .buildUnvalidated();
-        assertFalse(installer.install(incompleteBundle.getBytes()));
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(incompleteBundle.getBytes()));
         assertBundleInstalled(installedBundle);
     }
 
@@ -194,8 +218,10 @@
         assertTrue(workingDir.mkdir());
         createFile(new File(workingDir, "myFile"), new byte[] { 'a' });
 
-        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
-        assertTrue(installer.install(bundle.getBytes()));
+        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertBundleInstalled(bundle);
     }
 
@@ -204,10 +230,12 @@
      */
     public void testInstall_withMissingBundleVersionFile() throws Exception {
         // Create a bundle without a version file.
-        TimeZoneBundle bundle = createValidTimeZoneBundleBuilder(NEW_RULES_VERSION, "001")
+        TimeZoneBundle bundle = createValidTimeZoneBundleBuilder(NEW_RULES_VERSION, 1)
                 .clearVersionForTests()
                 .buildUnvalidated();
-        assertFalse(installer.install(bundle.getBytes()));
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
@@ -216,10 +244,12 @@
      */
     public void testInstall_withNewerBundleVersion() throws Exception {
         // Create a bundle that will appear to be newer than the one currently supported.
-        TimeZoneBundle bundle = createValidTimeZoneBundleBuilder(NEW_RULES_VERSION, "001")
-                .setBundleVersionForTests("002.001")
+        TimeZoneBundle bundle = createValidTimeZoneBundleBuilder(NEW_RULES_VERSION, 1)
+                .replaceFormatVersionForTests(2, 1)
                 .buildUnvalidated();
-        assertFalse(installer.install(bundle.getBytes()));
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_FORMAT_VERSION,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
@@ -229,37 +259,46 @@
     public void testInstall_withBadlyFormedBundleVersion() throws Exception {
         // Create a bundle that has an invalid major bundle version. It should be 3 numeric
         // characters, "." and 3 more numeric characters.
-        String invalidBundleVersion = "A01.001";
-        byte[] versionBytes =
-                BundleVersion.getBytes(invalidBundleVersion, NEW_RULES_VERSION, "001");
-        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(versionBytes);
-        assertFalse(installer.install(bundle.getBytes()));
+        BundleVersion validBundleVersion = new BundleVersion(1, 1, NEW_RULES_VERSION, 1);
+        byte[] invalidFormatVersionBytes = validBundleVersion.toBytes();
+        invalidFormatVersionBytes[0] = 'A';
+
+        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(invalidFormatVersionBytes);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
     /**
-     * Tests that a bundle with a badly formed android revision will be rejected.
+     * Tests that a bundle with a badly formed revision will be rejected.
      */
-    public void testInstall_withBadlyFormedAndroidRevision() throws Exception {
-        // Create a bundle that has an invalid Android revision. It should be 3 numeric characters.
-        String invalidAndroidRevision = "A01";
-        byte[] versionBytes = BundleVersion.getBytes(BundleVersion.FULL_BUNDLE_FORMAT_VERSION,
-                NEW_RULES_VERSION, invalidAndroidRevision);
-        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(versionBytes);
-        assertFalse(installer.install(bundle.getBytes()));
+    public void testInstall_withBadlyFormedRevision() throws Exception {
+        // Create a bundle that has an invalid revision. It should be 3 numeric characters.
+        BundleVersion validBundleVersion = new BundleVersion(1, 1, NEW_RULES_VERSION, 1);
+        byte[] invalidRevisionBytes = validBundleVersion.toBytes();
+        invalidRevisionBytes[invalidRevisionBytes.length - 3] = 'A';
+
+        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(invalidRevisionBytes);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
     /**
-     * Tests that a bundle with a badly formed android revision will be rejected.
+     * Tests that a bundle with a badly formed rules version will be rejected.
      */
     public void testInstall_withBadlyFormedRulesVersion() throws Exception {
         // Create a bundle that has an invalid rules version. It should be in the form "2016c".
-        final String invalidRulesVersion = "203Bc";
-        byte[] versionBytes = BundleVersion.getBytes(BundleVersion.FULL_BUNDLE_FORMAT_VERSION,
-                invalidRulesVersion, "001");
-        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(versionBytes);
-        assertFalse(installer.install(bundle.getBytes()));
+        BundleVersion validBundleVersion = new BundleVersion(1, 1, NEW_RULES_VERSION, 1);
+        byte[] invalidRulesVersionBytes = validBundleVersion.toBytes();
+        invalidRulesVersionBytes[invalidRulesVersionBytes.length - 6] = 'B';
+
+        TimeZoneBundle bundle = createTimeZoneBundleWithVersionBytes(invalidRulesVersionBytes);
+        assertEquals(
+                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_BUNDLE_STRUCTURE,
+                installer.installWithErrorCode(bundle.getBytes()));
         assertNoContentInstalled();
     }
 
@@ -292,19 +331,22 @@
     }
 
     private static TimeZoneBundle createValidTimeZoneBundle(
-            String rulesVersion, String androidRevision) throws Exception {
-        return createValidTimeZoneBundleBuilder(rulesVersion, androidRevision).build();
+            String rulesVersion, int revision) throws Exception {
+        return createValidTimeZoneBundleBuilder(rulesVersion, revision).build();
     }
 
     private static TimeZoneBundleBuilder createValidTimeZoneBundleBuilder(
-            String rulesVersion, String androidRevision) throws Exception {
+            String rulesVersion, int revision) throws Exception {
 
         byte[] bionicTzData = createTzData(rulesVersion);
         byte[] icuData = new byte[] { 'a' };
-
+        BundleVersion bundleVersion = new BundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION,
+                rulesVersion,
+                revision);
         return new TimeZoneBundleBuilder()
-                .setRulesVersion(rulesVersion)
-                .setAndroidRevision(androidRevision)
+                .setBundleVersion(bundleVersion)
                 .setTzData(bionicTzData)
                 .setIcuData(icuData);
     }
@@ -396,7 +438,7 @@
             throws Exception {
 
         // Create a valid bundle, then manipulate the version file.
-        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, "001");
+        TimeZoneBundle bundle = createValidTimeZoneBundle(NEW_RULES_VERSION, 1);
         byte[] bundleBytes = bundle.getBytes();
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream(bundleBytes.length);
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleTest.java
index 6aaf199..0e0b13b 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleTest.java
@@ -49,12 +49,12 @@
     }
 
     public void testGetBundleVersion() throws Exception {
-        BundleVersion bundleVersion =
-                new BundleVersion(BundleVersion.FULL_BUNDLE_FORMAT_VERSION, "2016c", "001");
+        BundleVersion bundleVersion = new BundleVersion(BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION, "2016c", 1);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try (ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) {
             addZipEntry(zipOutputStream, TimeZoneBundle.BUNDLE_VERSION_FILE_NAME,
-                    bundleVersion.getBytes());
+                    bundleVersion.toBytes());
         }
 
         TimeZoneBundle bundle = new TimeZoneBundle(baos.toByteArray());