Merge "Updating information for OkHttp suppressions"
diff --git a/benchmarks/src/benchmarks/regression/IcuBenchmark.java b/benchmarks/src/benchmarks/regression/IcuBenchmark.java
index ee8270a..2aed36b 100644
--- a/benchmarks/src/benchmarks/regression/IcuBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/IcuBenchmark.java
@@ -26,7 +26,7 @@
 public class IcuBenchmark extends SimpleBenchmark {
   public void time_getBestDateTimePattern(int reps) throws Exception {
     for (int rep = 0; rep < reps; ++rep) {
-      ICU.getBestDateTimePattern("dEEEMMM", "US");
+      ICU.getBestDateTimePattern("dEEEMMM", new Locale("en", "US"));
     }
   }
 }
diff --git a/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java b/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
index cde257b..ae6b6b6 100644
--- a/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
@@ -106,13 +106,13 @@
 
     public void timeToUpperCase_ICU(int reps) {
         for (int i = 0; i < reps; ++i) {
-            libcore.icu.ICU.toUpperCase(s.value, Locale.US.toString());
+            libcore.icu.ICU.toUpperCase(s.value, Locale.US);
         }
     }
 
     public void timeToLowerCase_ICU(int reps) {
         for (int i = 0; i < reps; ++i) {
-            libcore.icu.ICU.toLowerCase(s.value, Locale.US.toString());
+            libcore.icu.ICU.toLowerCase(s.value, Locale.US);
         }
     }
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index 6a75746..e3e1207 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -18,7 +18,6 @@
 package org.apache.harmony.tests.java.net;
 
 import java.io.IOException;
-import java.io.InterruptedIOException;
 import java.net.BindException;
 import java.net.DatagramPacket;
 import java.net.Inet4Address;
@@ -29,8 +28,10 @@
 import java.net.NetworkInterface;
 import java.net.SocketAddress;
 import java.net.SocketException;
+import java.net.SocketTimeoutException;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.List;
 
 public class MulticastSocketTest extends junit.framework.TestCase {
 
@@ -52,158 +53,124 @@
     private static InetAddress GOOD_IPv6 = lookup("ff05::7:7");
     private static InetAddress BAD_IPv6 = lookup("ff05::7:8");
 
-    static class MulticastServer extends Thread {
+    private NetworkInterface loopbackInterface;
+    private NetworkInterface ipv4NetworkInterface;
+    private NetworkInterface ipv6NetworkInterface;
 
-        public final MulticastSocket ms;
-        public final byte[] rbuf = new byte[512];
-        public final DatagramPacket rdp;
-        private final InetAddress groupAddr;
-        private final NetworkInterface groupNI;
+    @Override
+    protected void setUp() throws Exception {
+        // The loopback interface isn't actually useful for sending/receiving multicast messages
+        // but it can be used as a dummy for tests where that does not matter.
+        loopbackInterface = NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress());
+        assertNotNull(loopbackInterface);
+        assertTrue(loopbackInterface.isLoopback());
+        assertFalse(loopbackInterface.supportsMulticast());
 
-        private volatile boolean running = true;
+        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+        assertNotNull(interfaces);
 
-        public MulticastServer(InetAddress anAddress, int aPort) throws java.io.IOException {
-            rbuf[0] = -1;
-            rdp = new DatagramPacket(rbuf, rbuf.length);
-            ms = new MulticastSocket(aPort);
-            ms.setSoTimeout(2000);
-
-            groupAddr = anAddress;
-            groupNI = null;
-
-            ms.joinGroup(groupAddr);
-        }
-
-        public MulticastServer(InetAddress anAddress, int aPort,
-                NetworkInterface netInterface) throws java.io.IOException {
-            rbuf[0] = -1;
-            rdp = new DatagramPacket(rbuf, rbuf.length);
-            ms = new MulticastSocket(aPort);
-            ms.setSoTimeout(2000);
-
-            groupAddr = anAddress;
-            groupNI = netInterface;
-
-            ms.joinGroup(new InetSocketAddress(groupAddr, ms.getLocalPort()), groupNI);
-        }
-
-        public void run() {
-            try {
-                byte[] tmpbuf = new byte[512];
-                DatagramPacket tmpPack = new DatagramPacket(tmpbuf, tmpbuf.length);
-
-                while (running) {
-                    try {
-                        ms.receive(tmpPack);
-                        System.arraycopy(tmpPack.getData(), 0, rdp.getData(), rdp.getOffset(),
-                                tmpPack.getLength());
-                        rdp.setLength(tmpPack.getLength());
-                        rdp.setAddress(tmpPack.getAddress());
-                        rdp.setPort(tmpPack.getPort());
-                    } catch (InterruptedIOException e) {
+        while (interfaces.hasMoreElements()
+                && (ipv4NetworkInterface == null || ipv6NetworkInterface == null)) {
+            NetworkInterface nextInterface = interfaces.nextElement();
+            if (willWorkForMulticast(nextInterface)) {
+                Enumeration<InetAddress> addresses = nextInterface.getInetAddresses();
+                while (addresses.hasMoreElements()) {
+                    final InetAddress nextAddress = addresses.nextElement();
+                    if (nextAddress instanceof Inet6Address && ipv6NetworkInterface == null) {
+                        ipv6NetworkInterface = nextInterface;
+                    } else if (nextAddress instanceof Inet4Address && ipv4NetworkInterface == null) {
+                        ipv4NetworkInterface = nextInterface;
                     }
                 }
-            } catch (java.io.IOException e) {
-                fail();
-            } finally {
-                ms.close();
             }
         }
-
-        public void stopServer() {
-            running = false;
-            try {
-                ms.leaveGroup(groupAddr);
-            } catch (IOException e) {
-            }
-        }
+        assertTrue("Test environment must have at least one interface capable of multicast for IPv4"
+                + " and IPv6",
+                ipv4NetworkInterface != null && ipv6NetworkInterface != null);
     }
 
-    private NetworkInterface loopbackInterface;
-    private NetworkInterface networkInterface1;
-    private NetworkInterface IPV6networkInterface1;
-
     public void test_Constructor() throws IOException {
-        // regression test for 497
+        // Regression test for 497.
         MulticastSocket s = new MulticastSocket();
-        // regression test for Harmony-1162
+        // Regression test for Harmony-1162.
         assertTrue(s.getReuseAddress());
+
+        s.close();
     }
 
     public void test_ConstructorI() throws IOException {
         MulticastSocket orig = new MulticastSocket();
         int port = orig.getLocalPort();
         orig.close();
-        MulticastSocket dup = null;
-        try {
-            dup = new MulticastSocket(port);
-            // regression test for Harmony-1162
-            assertTrue(dup.getReuseAddress());
-        } catch (IOException e) {
-            fail("duplicate binding not allowed: " + e);
-        }
-        if (dup != null) {
-            dup.close();
-        }
+
+        MulticastSocket dup = new MulticastSocket(port);
+        // Regression test for Harmony-1162.
+        assertTrue(dup.getReuseAddress());
+        dup.close();
     }
 
     public void test_getInterface() throws Exception {
-        // validate that we get the expected response when one was not set
+        // Validate that we get the expected response when one was not set.
         MulticastSocket mss = new MulticastSocket(0);
-        // we expect an ANY address in this case
+        // We expect an ANY address in this case.
         assertTrue(mss.getInterface().isAnyLocalAddress());
 
-        // validate that we get the expected response when we set via
-        // setInterface
-        Enumeration addresses = networkInterface1.getInetAddresses();
+        // Validate that we get the expected response when we set via setInterface.
+        Enumeration addresses = ipv4NetworkInterface.getInetAddresses();
         if (addresses.hasMoreElements()) {
             InetAddress firstAddress = (InetAddress) addresses.nextElement();
             mss.setInterface(firstAddress);
-            assertEquals("getNetworkInterface did not return interface set by setInterface", firstAddress, mss.getInterface());
+            assertEquals("getNetworkInterface did not return interface set by setInterface",
+                    firstAddress, mss.getInterface());
 
             mss.close();
             mss = new MulticastSocket(0);
-            mss.setNetworkInterface(networkInterface1);
-            assertEquals("getInterface did not return interface set by setNetworkInterface", networkInterface1, NetworkInterface.getByInetAddress(mss.getInterface()));
+            mss.setNetworkInterface(ipv4NetworkInterface);
+            assertEquals("getInterface did not return interface set by setNetworkInterface",
+                    ipv4NetworkInterface, NetworkInterface.getByInetAddress(mss.getInterface()));
         }
 
         mss.close();
     }
 
     public void test_getNetworkInterface() throws IOException {
-        // validate that we get the expected response when one was not set
+        // Validate that we get the expected response when one was not set.
         MulticastSocket mss = new MulticastSocket(0);
         NetworkInterface theInterface = mss.getNetworkInterface();
-        assertTrue("network interface returned wrong network interface when not set:" + theInterface,
+        assertTrue(
+                "network interface returned wrong network interface when not set:" + theInterface,
                 theInterface.getInetAddresses().hasMoreElements());
-        InetAddress firstAddress = (InetAddress) theInterface.getInetAddresses().nextElement();
-        // validate we the first address in the network interface is the ANY address
+        InetAddress firstAddress = theInterface.getInetAddresses().nextElement();
+        // Validate we the first address in the network interface is the ANY address.
         assertTrue(firstAddress.isAnyLocalAddress());
 
-        mss.setNetworkInterface(networkInterface1);
+        mss.setNetworkInterface(ipv4NetworkInterface);
         assertEquals("getNetworkInterface did not return interface set by setNeworkInterface",
-                networkInterface1, mss.getNetworkInterface());
+                ipv4NetworkInterface, mss.getNetworkInterface());
 
         mss.setNetworkInterface(loopbackInterface);
-        assertEquals("getNetworkInterface did not return network interface set by second setNetworkInterface call",
+        assertEquals(
+                "getNetworkInterface did not return network interface set by second"
+                        + " setNetworkInterface call",
                 loopbackInterface, mss.getNetworkInterface());
         mss.close();
 
-        mss = new MulticastSocket(0);
-        if (IPV6networkInterface1 != null) {
-            mss.setNetworkInterface(IPV6networkInterface1);
+        if (ipv6NetworkInterface != null) {
+            mss = new MulticastSocket(0);
+            mss.setNetworkInterface(ipv6NetworkInterface);
             assertEquals("getNetworkInterface did not return interface set by setNeworkInterface",
-                    IPV6networkInterface1, mss.getNetworkInterface());
+                    ipv6NetworkInterface, mss.getNetworkInterface());
+            mss.close();
         }
 
-        // validate that we get the expected response when we set via setInterface
+        // Validate that we get the expected response when we set via setInterface.
         mss = new MulticastSocket(0);
-        Enumeration addresses = networkInterface1.getInetAddresses();
+        Enumeration addresses = ipv4NetworkInterface.getInetAddresses();
         if (addresses.hasMoreElements()) {
             firstAddress = (InetAddress) addresses.nextElement();
             mss.setInterface(firstAddress);
             assertEquals("getNetworkInterface did not return interface set by setInterface",
-                    networkInterface1, mss.getNetworkInterface());
+                    ipv4NetworkInterface, mss.getNetworkInterface());
         }
         mss.close();
     }
@@ -214,12 +181,14 @@
         assertEquals("Returned incorrect 1st TTL", 120, mss.getTimeToLive());
         mss.setTimeToLive(220);
         assertEquals("Returned incorrect 2nd TTL", 220, mss.getTimeToLive());
+        mss.close();
     }
 
     public void test_getTTL() throws Exception {
         MulticastSocket mss = new MulticastSocket();
         mss.setTTL((byte) 120);
         assertEquals("Returned incorrect TTL", 120, mss.getTTL());
+        mss.close();
     }
 
     public void test_joinGroupLjava_net_InetAddress_IPv4() throws Exception {
@@ -231,19 +200,23 @@
     }
 
     private void test_joinGroupLjava_net_InetAddress(InetAddress group) throws Exception {
-        MulticastServer server = new MulticastServer(group, 0);
-        server.start();
-        Thread.sleep(1000);
+        MulticastSocket receivingSocket = createReceivingSocket(0);
+        receivingSocket.joinGroup(group);
+
         String msg = "Hello World";
-        MulticastSocket mss = new MulticastSocket(server.ms.getLocalPort());
-        DatagramPacket sdp = new DatagramPacket(msg.getBytes(), msg.length(), group,
-                server.ms.getLocalPort());
-        mss.send(sdp, (byte) 10);
-        Thread.sleep(1000);
-        String receivedMessage = new String(server.rdp.getData(), 0, server.rdp.getLength());
+        MulticastSocket sendingSocket = new MulticastSocket(receivingSocket.getLocalPort());
+        InetSocketAddress groupAddress =
+                new InetSocketAddress(group, receivingSocket.getLocalPort());
+        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+        sendingSocket.send(sdp, (byte) 10 /* ttl */);
+
+        DatagramPacket rdp = createReceiveDatagramPacket();
+        receivingSocket.receive(rdp);
+        String receivedMessage = extractMessage(rdp);
         assertEquals("Group member did not recv data", msg, receivedMessage);
-        mss.close();
-        server.stopServer();
+
+        sendingSocket.close();
+        receivingSocket.close();
     }
 
     public void test_joinGroup_null_null() throws Exception {
@@ -276,52 +249,64 @@
         mss.close();
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4() throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(GOOD_IPv4, BAD_IPv4);
+    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
+            throws Exception {
+        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+                ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6() throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(GOOD_IPv6, BAD_IPv6);
+    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
+            throws Exception {
+        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+                ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
     }
 
-    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(InetAddress group, InetAddress group2) throws Exception {
+    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+            NetworkInterface networkInterface, InetAddress group, InetAddress group2)
+            throws Exception {
         // Check that we can join a group using a null network interface.
-        MulticastSocket mss = new MulticastSocket(0);
-        SocketAddress groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
+        MulticastSocket sendingSocket = new MulticastSocket(0);
+        SocketAddress groupSockAddr = new InetSocketAddress(group, sendingSocket.getLocalPort());
+        sendingSocket.joinGroup(groupSockAddr, null);
+        sendingSocket.setTimeToLive(2);
 
-        mss.joinGroup(groupSockAddr, null);
-        mss.setTimeToLive(2);
-        Thread.sleep(1000);
+        MulticastSocket receivingSocket = createReceivingSocket(0);
+        InetSocketAddress groupAddress =
+                new InetSocketAddress(group, receivingSocket.getLocalPort());
+        receivingSocket.joinGroup(groupAddress, networkInterface);
 
-        // set up the server and join the group on networkInterface1
-        MulticastServer server = new MulticastServer(group, 0, networkInterface1);
-        server.start();
-        Thread.sleep(1000);
         String msg = "Hello World";
-        DatagramPacket sdp = new DatagramPacket(msg.getBytes(), msg.length(), group,
-                server.ms.getLocalPort());
-        mss.setTimeToLive(2);
-        mss.send(sdp);
-        Thread.sleep(1000);
-        // now validate that we received the data as expected
-        assertEquals("Group member did not recv data", msg, new String(server.rdp.getData(), 0, server.rdp.getLength()));
-        server.stopServer();
-        mss.close();
+        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+        sendingSocket.send(sdp);
 
-        server = new MulticastServer(group, 0, networkInterface1);
-        server.start();
-        Thread.sleep(1000);
+        DatagramPacket rdp = createReceiveDatagramPacket();
+        receivingSocket.receive(rdp);
+        // Now validate that we received the data as expected.
+        assertEquals("Group member did not recv data", msg, extractMessage(rdp));
+        receivingSocket.close();
+        sendingSocket.close();
 
-        mss = new MulticastSocket(0);
-        mss.setTimeToLive(10);
+        receivingSocket = createReceivingSocket(0);
+        groupAddress = new InetSocketAddress(group, receivingSocket.getLocalPort());
+        receivingSocket.joinGroup(groupAddress, networkInterface);
+
+        sendingSocket = new MulticastSocket(0);
+        sendingSocket.setTimeToLive(10);
         msg = "Hello World - Different Group";
-        sdp = new DatagramPacket(msg.getBytes(), msg.length(), group2, server.ms.getLocalPort());
-        mss.send(sdp);
-        Thread.sleep(1000);
-        assertFalse("Group member received data when sent on different group: ",
-                new String(server.rdp.getData(), 0, server.rdp.getLength()).equals(msg));
-        server.stopServer();
-        mss.close();
+        InetSocketAddress group2Address =
+                new InetSocketAddress(group2, receivingSocket.getLocalPort());
+        sdp = createSendDatagramPacket(group2Address, msg);
+        sendingSocket.send(sdp);
+
+        rdp = createReceiveDatagramPacket();
+        try {
+            receivingSocket.receive(rdp);
+            fail("Expected timeout");
+        } catch (SocketTimeoutException expected) {
+        }
+
+        receivingSocket.close();
+        sendingSocket.close();
     }
 
     public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface() throws Exception {
@@ -329,27 +314,19 @@
         // received on that interface. This test is only really useful on devices with multiple
         // non-loopback interfaces.
 
-        ArrayList<NetworkInterface> realInterfaces = new ArrayList<NetworkInterface>();
+        List<NetworkInterface> realInterfaces = new ArrayList<NetworkInterface>();
         Enumeration<NetworkInterface> theInterfaces = NetworkInterface.getNetworkInterfaces();
         while (theInterfaces.hasMoreElements()) {
             NetworkInterface thisInterface = theInterfaces.nextElement();
-            if (thisInterface.getInetAddresses().hasMoreElements()) {
+            // Skip interfaces that do not support multicast - there's no point in proving
+            // they cannot send / receive multicast messages.
+            if (willWorkForMulticast(thisInterface)) {
                 realInterfaces.add(thisInterface);
             }
         }
 
-        for (int i = 0; i < realInterfaces.size(); i++) {
-            NetworkInterface thisInterface = realInterfaces.get(i);
-            if (!thisInterface.supportsMulticast()) {
-                // Skip interfaces that do not support multicast - there's no point in proving
-                // they cannot send / receive multicast messages.
-                continue;
-            }
-
-            // get the first address on the interface
-
-            // start server which is joined to the group and has
-            // only asked for packets on this interface
+        for (NetworkInterface thisInterface : realInterfaces) {
+            // Find a suitable group IP and interface to use to sent packets to thisInterface.
             Enumeration<InetAddress> addresses = thisInterface.getInetAddresses();
 
             NetworkInterface sendingInterface = null;
@@ -358,57 +335,69 @@
                 InetAddress firstAddress = addresses.nextElement();
                 if (firstAddress instanceof Inet4Address) {
                     group = GOOD_IPv4;
-                    sendingInterface = networkInterface1;
+                    sendingInterface = ipv4NetworkInterface;
                 } else {
                     // if this interface only seems to support IPV6 addresses
                     group = GOOD_IPv6;
-                    sendingInterface = IPV6networkInterface1;
+                    sendingInterface = ipv6NetworkInterface;
                 }
             }
 
-            MulticastServer server = new MulticastServer(group, 0, thisInterface);
-            server.start();
-            Thread.sleep(1000);
+            // Create a receivingSocket which is joined to the group and has only asked for packets
+            // on thisInterface.
+            MulticastSocket receivingSocket = createReceivingSocket(0);
+            InetSocketAddress groupAddress =
+                    new InetSocketAddress(group, receivingSocket.getLocalPort());
+            receivingSocket.joinGroup(groupAddress, thisInterface);
 
-            // Now send out a package on interface networkInterface 1. We should
-            // only see the packet if we send it on interface 1
-            MulticastSocket mss = new MulticastSocket(0);
-            mss.setNetworkInterface(sendingInterface);
-            String msg = "Hello World - Again" + thisInterface.getName();
-            DatagramPacket sdp = new DatagramPacket(msg.getBytes(), msg.length(), group,
-                    server.ms.getLocalPort());
-            mss.send(sdp);
-            Thread.sleep(1000);
-            if (thisInterface.equals(sendingInterface)) {
+            // Now send out a packet on sendingInterface. We should only see the packet if we send
+            // it on thisInterface.
+            MulticastSocket sendingSocket = new MulticastSocket(0);
+            sendingSocket.setNetworkInterface(sendingInterface);
+            String msg = "Hello World - Again " + thisInterface.getName();
+            DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+            sendingSocket.send(sdp);
+
+            DatagramPacket rdp = createReceiveDatagramPacket();
+            try {
+                receivingSocket.receive(rdp);
+
+                // If the packet is received....
+                assertEquals(thisInterface, sendingInterface);
                 assertEquals("Group member did not recv data when bound on specific interface",
-                        msg, new String(server.rdp.getData(), 0, server.rdp.getLength()));
-            } else {
-                assertFalse("Group member received data on other interface when only asked for it on one interface: ",
-                        new String(server.rdp.getData(), 0, server.rdp.getLength()).equals(msg));
+                        msg, extractMessage(rdp));
+            } catch (SocketTimeoutException e) {
+                // If the packet was not received...
+                assertTrue(!thisInterface.equals(sendingInterface));
             }
 
-            server.stopServer();
-            mss.close();
+            receivingSocket.close();
+            sendingSocket.close();
         }
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4() throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(GOOD_IPv4);
+    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4()
+            throws Exception {
+        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+                ipv4NetworkInterface, GOOD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6() throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(GOOD_IPv6);
+    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6()
+            throws Exception {
+        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+                ipv6NetworkInterface, GOOD_IPv6);
     }
 
-    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(InetAddress group) throws Exception {
-        // validate that we can join the same address on two
-        // different interfaces but not on the same interface
+    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+            NetworkInterface networkInterface, InetAddress group) throws Exception {
+        // Validate that we can join the same address on two different interfaces but not on the
+        // same interface.
         MulticastSocket mss = new MulticastSocket(0);
         SocketAddress groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
-        mss.joinGroup(groupSockAddr, networkInterface1);
+        mss.joinGroup(groupSockAddr, networkInterface);
         mss.joinGroup(groupSockAddr, loopbackInterface);
         try {
-            mss.joinGroup(groupSockAddr, networkInterface1);
+            mss.joinGroup(groupSockAddr, networkInterface);
             fail("Did not get expected exception when joining for second time on same interface");
         } catch (IOException e) {
         }
@@ -426,9 +415,9 @@
     private void test_leaveGroupLjava_net_InetAddress(InetAddress group) throws Exception {
         String msg = "Hello World";
         MulticastSocket mss = new MulticastSocket(0);
-        DatagramPacket sdp = new DatagramPacket(msg.getBytes(), msg.length(), group,
-                mss.getLocalPort());
-        mss.send(sdp, (byte) 10);
+        InetSocketAddress groupAddress = new InetSocketAddress(group, mss.getLocalPort());
+        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+        mss.send(sdp, (byte) 10 /* ttl */);
         try {
             // Try to leave a group we didn't join.
             mss.leaveGroup(group);
@@ -468,15 +457,21 @@
         mss.close();
     }
 
-    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4() throws Exception {
-        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(GOOD_IPv4, BAD_IPv4);
+    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
+            throws Exception {
+        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+                ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
     }
 
-    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6() throws Exception {
-        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(GOOD_IPv6, BAD_IPv6);
+    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
+            throws Exception {
+        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+                ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
     }
 
-    private void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(InetAddress group, InetAddress group2) throws Exception {
+    private void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+            NetworkInterface networkInterface, InetAddress group, InetAddress group2)
+            throws Exception {
         SocketAddress groupSockAddr = null;
         SocketAddress groupSockAddr2 = null;
 
@@ -491,20 +486,20 @@
         }
 
         groupSockAddr2 = new InetSocketAddress(group2, mss.getLocalPort());
-        mss.joinGroup(groupSockAddr, networkInterface1);
+        mss.joinGroup(groupSockAddr, networkInterface);
         try {
-            mss.leaveGroup(groupSockAddr2, networkInterface1);
+            mss.leaveGroup(groupSockAddr2, networkInterface);
             fail("Did not get exception when trying to leave group that was never joined");
         } catch (IOException expected) {
         }
 
-        mss.leaveGroup(groupSockAddr, networkInterface1);
+        mss.leaveGroup(groupSockAddr, networkInterface);
 
-        mss.joinGroup(groupSockAddr, networkInterface1);
+        mss.joinGroup(groupSockAddr, networkInterface);
         try {
             mss.leaveGroup(groupSockAddr, loopbackInterface);
             fail("Did not get exception when trying to leave group on wrong interface " +
-                    "joined on [" + networkInterface1 + "] left on [" + loopbackInterface + "]");
+                    "joined on [" + networkInterface + "] left on [" + loopbackInterface + "]");
         } catch (IOException expected) {
         }
     }
@@ -519,31 +514,36 @@
 
     private void test_sendLjava_net_DatagramPacketB(InetAddress group) throws Exception {
         String msg = "Hello World";
-        MulticastSocket mss = new MulticastSocket(0);
-        MulticastServer server = new MulticastServer(group, mss.getLocalPort());
-        server.start();
-        Thread.sleep(200);
-        DatagramPacket sdp = new DatagramPacket(msg.getBytes(), msg.length(), group, mss.getLocalPort());
-        mss.send(sdp, (byte) 10);
-        Thread.sleep(1000);
-        mss.close();
-        byte[] data = server.rdp.getData();
-        int length = server.rdp.getLength();
-        assertEquals("Failed to send data. Received " + length, msg, new String(data, 0, length));
-        server.stopServer();
+        MulticastSocket sendingSocket = new MulticastSocket(0);
+        MulticastSocket receivingSocket = createReceivingSocket(sendingSocket.getLocalPort());
+        receivingSocket.joinGroup(group);
+
+        InetSocketAddress groupAddress = new InetSocketAddress(group, sendingSocket.getLocalPort());
+        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+        sendingSocket.send(sdp, (byte) 10 /* ttl */);
+        sendingSocket.close();
+
+        DatagramPacket rdp = createReceiveDatagramPacket();
+        receivingSocket.receive(rdp);
+        String receivedMessage = extractMessage(rdp);
+        assertEquals("Failed to send data. Received " + rdp.getLength(), msg, receivedMessage);
+        receivingSocket.close();
     }
 
     public void test_setInterfaceLjava_net_InetAddress() throws Exception {
         MulticastSocket mss = new MulticastSocket();
         mss.setInterface(InetAddress.getLocalHost());
         InetAddress theInterface = mss.getInterface();
-        // under IPV6 we are not guarrenteed to get the same address back as
-        // the address, all we should be guaranteed is that we get an
-        // address on the same interface
+        // Under IPV6 we are not guaranteed to get the same address back as the address that was
+        // set, all we should be guaranteed is that we get an address on the same interface.
         if (theInterface instanceof Inet6Address) {
-            assertTrue("Failed to return correct interface IPV6", NetworkInterface.getByInetAddress(mss.getInterface()).equals(NetworkInterface.getByInetAddress(theInterface)));
+            assertEquals("Failed to return correct interface IPV6",
+                    NetworkInterface.getByInetAddress(mss.getInterface()),
+                    NetworkInterface.getByInetAddress(theInterface));
         } else {
-            assertTrue("Failed to return correct interface IPV4 got:" + mss.getInterface() + " excpeted: " + InetAddress.getLocalHost(), mss.getInterface().equals(InetAddress.getLocalHost()));
+            assertTrue("Failed to return correct interface IPV4 got:" + mss.getInterface() +
+                    " expected: " + InetAddress.getLocalHost(),
+                    mss.getInterface().equals(InetAddress.getLocalHost()));
         }
         mss.close();
     }
@@ -556,7 +556,7 @@
         test_setInterface_unbound_address(GOOD_IPv6);
     }
 
-    // Regression test for Harmony-2410
+    // Regression test for Harmony-2410.
     private void test_setInterface_unbound_address(InetAddress address) throws Exception {
         MulticastSocket mss = new MulticastSocket();
         try {
@@ -568,7 +568,7 @@
     }
 
     public void test_setNetworkInterfaceLjava_net_NetworkInterface_null() throws Exception {
-        // validate that null interface is handled ok
+        // Validate that null interface is handled ok.
         MulticastSocket mss = new MulticastSocket();
         try {
             mss.setNetworkInterface(null);
@@ -579,10 +579,11 @@
     }
 
     public void test_setNetworkInterfaceLjava_net_NetworkInterface_round_trip() throws Exception {
-        // validate that we can get and set the interface
+        // Validate that we can get and set the interface.
         MulticastSocket mss = new MulticastSocket();
-        mss.setNetworkInterface(networkInterface1);
-        assertEquals("Interface did not seem to be set by setNeworkInterface", networkInterface1, mss.getNetworkInterface());
+        mss.setNetworkInterface(ipv4NetworkInterface);
+        assertEquals("Interface did not seem to be set by setNeworkInterface",
+                ipv4NetworkInterface, mss.getNetworkInterface());
         mss.close();
     }
 
@@ -594,35 +595,35 @@
         test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv6);
     }
 
-    private void test_setNetworkInterfaceLjava_net_NetworkInterface(InetAddress group) throws IOException, InterruptedException {
-        // set up the server and join the group
+    private void test_setNetworkInterfaceLjava_net_NetworkInterface(InetAddress group)
+            throws IOException, InterruptedException {
+        // Set up the receiving socket and join the group.
         Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces();
         while (theInterfaces.hasMoreElements()) {
             NetworkInterface thisInterface = (NetworkInterface) theInterfaces.nextElement();
             if (thisInterface.getInetAddresses().hasMoreElements() && thisInterface.isUp()) {
                 if ((!(thisInterface.getInetAddresses().nextElement()).isLoopbackAddress())) {
-                    MulticastServer server = new MulticastServer(group, 0);
-                    server.start();
-                    // give the server some time to start up
-                    Thread.sleep(1000);
+                    MulticastSocket receivingSocket = createReceivingSocket(0);
+                    InetSocketAddress groupAddress =
+                            new InetSocketAddress(group, receivingSocket.getLocalPort());
+                    receivingSocket.joinGroup(groupAddress, thisInterface);
 
-                    // Send the packets on a particular interface. The
-                    // source address in the received packet
-                    // should be one of the addresses for the interface
-                    // set
-                    MulticastSocket mss = new MulticastSocket(0);
-                    mss.setNetworkInterface(thisInterface);
+                    // Send the packets on a particular interface. The source address in the
+                    // received packet should be one of the addresses for the interface set.
+                    MulticastSocket sendingSocket = new MulticastSocket(0);
+                    sendingSocket.setNetworkInterface(thisInterface);
                     String msg = thisInterface.getName();
-                    byte theBytes[] = msg.getBytes();
-                    DatagramPacket sdp = new DatagramPacket(theBytes, theBytes.length, group,
-                            server.ms.getLocalPort());
-                    mss.send(sdp);
-                    Thread.sleep(1000);
-                    String receivedMessage = new String(server.rdp.getData(), 0, server.rdp.getLength());
-                    assertEquals("Group member did not recv data sent on a specific interface", msg, receivedMessage);
-                    // stop the server
-                    server.stopServer();
-                    mss.close();
+                    DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
+                    sendingSocket.send(sdp);
+
+                    DatagramPacket rdp = createReceiveDatagramPacket();
+                    receivingSocket.receive(rdp);
+                    String receivedMessage = extractMessage(rdp);
+                    assertEquals("Group member did not recv data sent on a specific interface",
+                            msg, receivedMessage);
+                    // Stop the server.
+                    receivingSocket.close();
+                    sendingSocket.close();
                 }
             }
         }
@@ -651,24 +652,28 @@
         assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
         ms.close();
         assertTrue("should be closed", ms.isClosed());
+
         ms = new MulticastSocket(0);
         assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
         ms.close();
         assertTrue("should be closed", ms.isClosed());
+
         ms = new MulticastSocket(0);
         assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
         ms.close();
         assertTrue("should be closed", ms.isClosed());
+
         try {
-            ms = new MulticastSocket(new InetSocketAddress("unresolvedname", 31415));
+            new MulticastSocket(new InetSocketAddress("unresolvedname", 31415));
             fail();
         } catch (IOException expected) {
         }
 
-        // regression test for Harmony-1162
+        // Regression test for Harmony-1162.
         InetSocketAddress addr = new InetSocketAddress("0.0.0.0", 0);
         MulticastSocket s = new MulticastSocket(addr);
         assertTrue(s.getReuseAddress());
+        s.close();
     }
 
     public void test_getLoopbackMode() throws Exception {
@@ -699,129 +704,69 @@
     }
 
     private void test_setLoopbackModeSendReceive(InetAddress group) throws IOException {
+        // Test send receive.
         final String message = "Hello, world!";
 
-        // test send receive
         MulticastSocket socket = new MulticastSocket(0);
         socket.setLoopbackMode(false); // false indicates doing loop back
         socket.joinGroup(group);
 
-        // send the datagram
-        byte[] sendData = message.getBytes();
-        DatagramPacket sendDatagram = new DatagramPacket(sendData, 0, sendData.length,
-                new InetSocketAddress(group, socket.getLocalPort()));
+        // Send the datagram.
+        InetSocketAddress groupAddress = new InetSocketAddress(group, socket.getLocalPort());
+        DatagramPacket sendDatagram = createSendDatagramPacket(groupAddress, message);
         socket.send(sendDatagram);
 
-        // receive the datagram
-        byte[] recvData = new byte[100];
-        DatagramPacket recvDatagram = new DatagramPacket(recvData, recvData.length);
-        socket.setSoTimeout(5000); // prevent eternal block in
+        // Receive the datagram.
+        DatagramPacket recvDatagram = createReceiveDatagramPacket();
+        socket.setSoTimeout(5000); // Prevent eternal block in.
         socket.receive(recvDatagram);
-        String recvMessage = new String(recvData, 0, recvDatagram.getLength());
+        String recvMessage = extractMessage(recvDatagram);
         assertEquals(message, recvMessage);
         socket.close();
     }
 
     public void test_setReuseAddressZ() throws Exception {
-        // test case were we set it to false
-        MulticastSocket theSocket1 = null;
-        MulticastSocket theSocket2 = null;
+        // Test case were we to set ReuseAddress to false.
+        MulticastSocket theSocket1 = new MulticastSocket(null);
+        theSocket1.setReuseAddress(false);
+
+        MulticastSocket theSocket2 = new MulticastSocket(null);
+        theSocket2.setReuseAddress(false);
+
+        InetSocketAddress addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
+        theSocket1.bind(addr);
+        addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
         try {
-            theSocket1 = new MulticastSocket(null);
-            theSocket2 = new MulticastSocket(null);
-            theSocket1.setReuseAddress(false);
-            theSocket2.setReuseAddress(false);
-            InetSocketAddress addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
-            theSocket1.bind(addr);
-            addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
             theSocket2.bind(addr);
-            fail("No exception when trying to connect to do duplicate socket bind with re-useaddr set to false");
+            fail("No exception when trying to connect to do duplicate socket bind with re-useaddr"
+                    + " set to false");
         } catch (BindException expected) {
         }
-        if (theSocket1 != null) {
-            theSocket1.close();
-        }
-        if (theSocket2 != null) {
-            theSocket2.close();
-        }
+        theSocket1.close();
+        theSocket2.close();
 
-        // test case were we set it to true
+        // Test case were we set it to true.
         theSocket1 = new MulticastSocket(null);
         theSocket2 = new MulticastSocket(null);
         theSocket1.setReuseAddress(true);
         theSocket2.setReuseAddress(true);
-        InetSocketAddress addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
+        addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
         theSocket1.bind(addr);
         addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
         theSocket2.bind(addr);
 
-        if (theSocket1 != null) {
-            theSocket1.close();
-        }
-        if (theSocket2 != null) {
-            theSocket2.close();
-        }
+        theSocket1.close();
+        theSocket2.close();
 
-        // test the default case which we expect to be
-        // the same on all platforms
+        // Test the default case which we expect to be the same on all platforms.
         theSocket1 = new MulticastSocket(null);
         theSocket2 = new MulticastSocket(null);
         addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
         theSocket1.bind(addr);
         addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
         theSocket2.bind(addr);
-        if (theSocket1 != null) {
-            theSocket1.close();
-        }
-        if (theSocket2 != null) {
-            theSocket2.close();
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        // The loopback interface isn't actually useful for sending/receiving multicast messages
-        // but it can be used as a dummy for tests where that does not matter.
-        loopbackInterface = NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress());
-        assertNotNull(loopbackInterface);
-        assertTrue(loopbackInterface.isLoopback());
-        assertFalse(loopbackInterface.supportsMulticast());
-
-        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
-
-        // only consider interfaces that have addresses associated with them.
-        // Otherwise tests don't work so well
-        if (interfaces != null) {
-            boolean atLeastOneInterface = false;
-            while (interfaces.hasMoreElements() && (atLeastOneInterface == false)) {
-                networkInterface1 = interfaces.nextElement();
-                if (willWorkForMulticast(networkInterface1)) {
-                    atLeastOneInterface = true;
-                }
-            }
-
-            assertTrue("Test environment must have at least one environment capable of multicast",
-                    atLeastOneInterface);
-
-            // Find the first multicast-compatible interface that supports IPV6 if one exists
-            interfaces = NetworkInterface.getNetworkInterfaces();
-
-            boolean found = false;
-            while (interfaces.hasMoreElements() && !found) {
-                NetworkInterface nextInterface = interfaces.nextElement();
-                if (willWorkForMulticast(nextInterface)) {
-                    Enumeration<InetAddress> addresses = nextInterface.getInetAddresses();
-                    while (addresses.hasMoreElements()) {
-                        final InetAddress nextAddress = addresses.nextElement();
-                        if (nextAddress instanceof Inet6Address) {
-                            IPV6networkInterface1 = nextInterface;
-                            found = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
+        theSocket1.close();
+        theSocket2.close();
     }
 
     private static boolean willWorkForMulticast(NetworkInterface iface) throws IOException {
@@ -831,4 +776,26 @@
                 && !iface.isLoopback() && iface.supportsMulticast()
                 && iface.getInetAddresses().hasMoreElements();
     }
+
+    private static MulticastSocket createReceivingSocket(int aPort) throws IOException {
+        MulticastSocket ms = new MulticastSocket(aPort);
+        ms.setSoTimeout(2000);
+        return ms;
+    }
+
+    private static DatagramPacket createReceiveDatagramPacket() {
+        byte[] rbuf = new byte[512];
+        return new DatagramPacket(rbuf, rbuf.length);
+    }
+
+    private static DatagramPacket createSendDatagramPacket(
+            InetSocketAddress groupAndPort, String msg) {
+        return new DatagramPacket(
+                msg.getBytes(), msg.length(), groupAndPort.getAddress(), groupAndPort.getPort());
+    }
+
+    private static String extractMessage(DatagramPacket rdp) {
+        return new String(rdp.getData(), 0, rdp.getLength());
+    }
+
 }
diff --git a/include/ScopedIcuLocale.h b/include/ScopedIcuLocale.h
new file mode 100644
index 0000000..2109e03
--- /dev/null
+++ b/include/ScopedIcuLocale.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef SCOPED_ICU_LOCALE_H_included
+#define SCOPED_ICU_LOCALE_H_included
+
+#include "JNIHelp.h"
+#include "ScopedUtfChars.h"
+#include "unicode/locid.h"
+
+class ScopedIcuLocale {
+ public:
+  ScopedIcuLocale(JNIEnv* env, jstring javaLocaleName) : mEnv(env) {
+    mLocale.setToBogus();
+
+    if (javaLocaleName == NULL) {
+      jniThrowNullPointerException(mEnv, "javaLocaleName == null");
+      return;
+    }
+
+    const ScopedUtfChars localeName(env, javaLocaleName);
+    if (localeName.c_str() == NULL) {
+      return;
+    }
+
+    mLocale = Locale::createFromName(localeName.c_str());
+  }
+
+  ~ScopedIcuLocale() {
+  }
+
+  bool valid() const {
+    return !mLocale.isBogus();
+  }
+
+  Locale& locale() {
+    return mLocale;
+  }
+
+ private:
+  JNIEnv* const mEnv;
+  Locale mLocale;
+
+  // Disallow copy and assignment.
+  ScopedIcuLocale(const ScopedIcuLocale&);
+  void operator=(const ScopedIcuLocale&);
+};
+
+#endif  // SCOPED_ICU_LOCALE_H_included
diff --git a/luni/src/main/java/java/lang/CaseMapper.java b/luni/src/main/java/java/lang/CaseMapper.java
index 4e411d1..1da621c 100644
--- a/luni/src/main/java/java/lang/CaseMapper.java
+++ b/luni/src/main/java/java/lang/CaseMapper.java
@@ -49,7 +49,7 @@
         // Note that Greek isn't a particularly hard case for toLowerCase, only toUpperCase.
         String languageCode = locale.getLanguage();
         if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
-            return ICU.toLowerCase(s, locale.toString());
+            return ICU.toLowerCase(s, locale);
         }
 
         char[] newValue = null;
@@ -59,7 +59,7 @@
             char newCh;
             if (ch == LATIN_CAPITAL_I_WITH_DOT || Character.isHighSurrogate(ch)) {
                 // Punt these hard cases.
-                return ICU.toLowerCase(s, locale.toString());
+                return ICU.toLowerCase(s, locale);
             } else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(value, offset, count, i)) {
                 newCh = GREEK_SMALL_FINAL_SIGMA;
             } else {
@@ -150,7 +150,7 @@
     public static String toUpperCase(Locale locale, String s, char[] value, int offset, int count) {
         String languageCode = locale.getLanguage();
         if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
-            return ICU.toUpperCase(s, locale.toString());
+            return ICU.toUpperCase(s, locale);
         }
         if (languageCode.equals("el")) {
             return EL_UPPER.get().transliterate(s);
@@ -161,7 +161,7 @@
         for (int o = offset, end = offset + count; o < end; o++) {
             char ch = value[o];
             if (Character.isHighSurrogate(ch)) {
-                return ICU.toUpperCase(s, locale.toString());
+                return ICU.toUpperCase(s, locale);
             }
             int index = upperIndex(ch);
             if (index == -1) {
diff --git a/luni/src/main/java/java/lang/Character.java b/luni/src/main/java/java/lang/Character.java
index 59931f6..f088c24 100644
--- a/luni/src/main/java/java/lang/Character.java
+++ b/luni/src/main/java/java/lang/Character.java
@@ -1535,6 +1535,7 @@
      * don't have a corresponding {@code UnicodeScript} will be in {@code UNKNOWN}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public static enum UnicodeScript {
         /** ISO 15924 English name "Arabic" */
diff --git a/luni/src/main/java/java/net/HttpCookie.java b/luni/src/main/java/java/net/HttpCookie.java
index 1d8a8cc..3748b9f 100644
--- a/luni/src/main/java/java/net/HttpCookie.java
+++ b/luni/src/main/java/java/net/HttpCookie.java
@@ -564,6 +564,7 @@
      * to scripts in a browser.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public boolean isHttpOnly() {
         return httpOnly;
@@ -574,6 +575,7 @@
      * to scripts in a browser.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public void setHttpOnly(boolean httpOnly) {
         this.httpOnly = httpOnly;
diff --git a/luni/src/main/java/java/net/SocketOption.java b/luni/src/main/java/java/net/SocketOption.java
index bc3e101..2bd4c6d 100644
--- a/luni/src/main/java/java/net/SocketOption.java
+++ b/luni/src/main/java/java/net/SocketOption.java
@@ -27,6 +27,7 @@
  *
  * @param <T> the type of the value
  * @since 1.7
+ * @hide 1.7
  */
 public interface SocketOption<T> {
 
diff --git a/luni/src/main/java/java/net/StandardSocketOptions.java b/luni/src/main/java/java/net/StandardSocketOptions.java
index a793f66..d61d937 100644
--- a/luni/src/main/java/java/net/StandardSocketOptions.java
+++ b/luni/src/main/java/java/net/StandardSocketOptions.java
@@ -32,6 +32,7 @@
  * for each type of socket.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public final class StandardSocketOptions {
 
diff --git a/luni/src/main/java/java/net/URLConnection.java b/luni/src/main/java/java/net/URLConnection.java
index d24e273..5147b7b 100644
--- a/luni/src/main/java/java/net/URLConnection.java
+++ b/luni/src/main/java/java/net/URLConnection.java
@@ -320,6 +320,7 @@
      * {@code content-length} or {@code -1} if this field is not set.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public long getContentLengthLong() {
         return getHeaderFieldLong("Content-Length", -1);
@@ -567,6 +568,7 @@
      *            the default value if no field has been found.
      * @return the value of the specified header field as a number.
      * @since 1.7
+     * @hide 1.7
      */
     public long getHeaderFieldLong(String field, long defaultValue) {
         try {
diff --git a/luni/src/main/java/java/nio/channels/AlreadyBoundException.java b/luni/src/main/java/java/nio/channels/AlreadyBoundException.java
index 70c70ac..e76b574 100644
--- a/luni/src/main/java/java/nio/channels/AlreadyBoundException.java
+++ b/luni/src/main/java/java/nio/channels/AlreadyBoundException.java
@@ -19,6 +19,9 @@
 /**
  * An {@code AlreadyBoundException} is thrown when an attempt is made to bind a NetworkChannel that
  * is already bound.
+ *
+ * @since 1.7
+ * @hide 1.7
  */
 public class AlreadyBoundException extends IllegalStateException {
 
diff --git a/luni/src/main/java/java/nio/channels/DatagramChannel.java b/luni/src/main/java/java/nio/channels/DatagramChannel.java
index b0cc2ac..7278655 100644
--- a/luni/src/main/java/java/nio/channels/DatagramChannel.java
+++ b/luni/src/main/java/java/nio/channels/DatagramChannel.java
@@ -92,6 +92,10 @@
      */
     public abstract DatagramSocket socket();
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public DatagramChannel bind(SocketAddress local) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -99,6 +103,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public SocketAddress getLocalAddress() throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -106,6 +114,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> T getOption(SocketOption<T> option) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -113,6 +125,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> DatagramChannel setOption(SocketOption<T> option, T value) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -120,6 +136,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public Set<SocketOption<?>> supportedOptions() {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -127,6 +147,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public MembershipKey join(InetAddress groupAddress, NetworkInterface networkInterface)
             throws IOException {
@@ -135,6 +159,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public MembershipKey join(InetAddress groupAddress, NetworkInterface networkInterface,
             InetAddress sourceAddress) throws IOException {
diff --git a/luni/src/main/java/java/nio/channels/FileChannel.java b/luni/src/main/java/java/nio/channels/FileChannel.java
index 3989167..59dc26e 100644
--- a/luni/src/main/java/java/nio/channels/FileChannel.java
+++ b/luni/src/main/java/java/nio/channels/FileChannel.java
@@ -77,7 +77,7 @@
  * content, size, etc.
  */
 public abstract class FileChannel extends AbstractInterruptibleChannel
-        implements GatheringByteChannel, ScatteringByteChannel, SeekableByteChannel {
+        implements ByteChannel, GatheringByteChannel, ScatteringByteChannel, SeekableByteChannel {
 
     /**
      * {@code MapMode} defines file mapping mode constants.
diff --git a/luni/src/main/java/java/nio/channels/FileLock.java b/luni/src/main/java/java/nio/channels/FileLock.java
index d1ba872..986527c 100644
--- a/luni/src/main/java/java/nio/channels/FileLock.java
+++ b/luni/src/main/java/java/nio/channels/FileLock.java
@@ -107,7 +107,7 @@
     }
 
     /**
-     * Returns the lock's {@link FileChannel}. This method has been superseded by {@link #acquiredBy()}.
+     * Returns the lock's {@link FileChannel}.
      */
     public final FileChannel channel() {
         return channel;
@@ -117,7 +117,9 @@
      * Returns the {@link Channel} that holds this lock.
      *
      * @since 1.7
+     * @hide 1.7
      */
+    // Add "This method has been superseded by {@link #acquiredBy()}." to channel when unhiding.
     public Channel acquiredBy() {
         return channel;
     }
diff --git a/luni/src/main/java/java/nio/channels/MembershipKey.java b/luni/src/main/java/java/nio/channels/MembershipKey.java
index a7eecac..ed8caad 100644
--- a/luni/src/main/java/java/nio/channels/MembershipKey.java
+++ b/luni/src/main/java/java/nio/channels/MembershipKey.java
@@ -36,6 +36,7 @@
  * Multicast Source Filters</a> for concepts and terminology associated with multicast membership.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public abstract class MembershipKey {
 
diff --git a/luni/src/main/java/java/nio/channels/MulticastChannel.java b/luni/src/main/java/java/nio/channels/MulticastChannel.java
index 47433d0..b8e6c8b 100644
--- a/luni/src/main/java/java/nio/channels/MulticastChannel.java
+++ b/luni/src/main/java/java/nio/channels/MulticastChannel.java
@@ -69,6 +69,7 @@
  * information.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public interface MulticastChannel extends NetworkChannel {
 
@@ -110,6 +111,8 @@
    *         if the channel is closed
    * @throws IOException
    *         if some other I/O error occurs
+   * @since 1.7
+   * @hide 1.7
    */
   MembershipKey join(InetAddress groupAddress, NetworkInterface networkInterface)
       throws IOException;
@@ -148,6 +151,8 @@
    *         if the channel is closed
    * @throws IOException
    *         if some other I/O error occurs
+   * @since 1.7
+   * @hide 1.7
    */
   MembershipKey join(
       InetAddress groupAddress, NetworkInterface networkInterface, InetAddress sourceAddress)
diff --git a/luni/src/main/java/java/nio/channels/NetworkChannel.java b/luni/src/main/java/java/nio/channels/NetworkChannel.java
index 3ae1e6b..31b81d5 100644
--- a/luni/src/main/java/java/nio/channels/NetworkChannel.java
+++ b/luni/src/main/java/java/nio/channels/NetworkChannel.java
@@ -26,6 +26,7 @@
  * A common interface for channels that are backed by network sockets.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public interface NetworkChannel extends AutoCloseable, Channel, Closeable {
 
@@ -45,14 +46,14 @@
    *     if the channel is already bound.
    * @throws IOException
    *     if another I/O error occurs.
+   * @hide 1.7
    */
   NetworkChannel bind(SocketAddress local) throws IOException;
 
   /**
    * Returns the local socket address the channel is bound to. The socket may be bound explicitly
-   * via {@link #bind(java.net.SocketAddress)} or similar methods, or as a side-effect when other
-   * methods are called, depending on the implementation. If the channel is not bound {@code null}
-   * is returned.
+   * with {@code bind} or as a side-effect when other methods are called, depending on the
+   * implementation. If the channel is not bound {@code null} is returned.
    *
    * <p>If IP is being used, the returned object will be a subclass of
    * {@link java.net.InetSocketAddress}
@@ -62,6 +63,7 @@
    *     if the channel is closed.
    * @throws IOException
    *     if another I/O error occurs.
+   * @hide 1.7
    */
   SocketAddress getLocalAddress() throws IOException;
 
@@ -75,6 +77,7 @@
    * @throws IOException
    *     if the value cannot be read.
    * @see java.net.StandardSocketOptions
+   * @hide 1.7
    */
   <T> T getOption(SocketOption<T> option) throws IOException;
 
@@ -91,11 +94,13 @@
    * @throws IOException
    *     if the value cannot be written.
    * @see java.net.StandardSocketOptions
+   * @hide 1.7
    */
   <T> NetworkChannel setOption(SocketOption<T> option, T value) throws IOException;
 
   /**
    * Returns the set of socket options supported by this channel.
+   * @hide 1.7
    */
   Set<SocketOption<?>> supportedOptions();
 }
diff --git a/luni/src/main/java/java/nio/channels/SeekableByteChannel.java b/luni/src/main/java/java/nio/channels/SeekableByteChannel.java
index da4671d..edd2645 100644
--- a/luni/src/main/java/java/nio/channels/SeekableByteChannel.java
+++ b/luni/src/main/java/java/nio/channels/SeekableByteChannel.java
@@ -34,6 +34,7 @@
  * be queried.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public interface SeekableByteChannel extends ByteChannel {
 
diff --git a/luni/src/main/java/java/nio/channels/ServerSocketChannel.java b/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
index 790344b..01adbc7 100644
--- a/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
+++ b/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
@@ -89,6 +89,8 @@
      * {@inheritDoc}
      *
      * <p>This is equivalent to {@code bind(local, 0)}.
+     * @since 1.7
+     * @hide 1.7
      */
     @Override
     public final ServerSocketChannel bind(SocketAddress local) throws IOException {
@@ -114,6 +116,7 @@
      * @throws IOException
      *             if another I/O error occurs.
      * @since 1.7
+     * @hide 1.7
      */
     public ServerSocketChannel bind(SocketAddress localAddr, int backlog) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -121,6 +124,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public SocketAddress getLocalAddress() throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -128,6 +135,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> T getOption(SocketOption<T> option) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -135,6 +146,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> ServerSocketChannel setOption(SocketOption<T> option, T value) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -142,6 +157,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public Set<SocketOption<?>> supportedOptions() {
         // This method was added for interoperability with Java 7, where it is abstract. It is
diff --git a/luni/src/main/java/java/nio/channels/SocketChannel.java b/luni/src/main/java/java/nio/channels/SocketChannel.java
index e96c6a1..9788c99 100644
--- a/luni/src/main/java/java/nio/channels/SocketChannel.java
+++ b/luni/src/main/java/java/nio/channels/SocketChannel.java
@@ -142,6 +142,10 @@
      */
     public abstract Socket socket();
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public SocketChannel bind(SocketAddress local) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -149,6 +153,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public SocketAddress getLocalAddress() throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -156,6 +164,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> T getOption(SocketOption<T> option) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -163,6 +175,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public <T> SocketChannel setOption(SocketOption<T> option, T value) throws IOException {
         // This method was added for interoperability with Java 7, where it is abstract. It is
@@ -170,6 +186,10 @@
         throw new UnsupportedOperationException("Subclasses must override this method");
     }
 
+    /**
+     * @since 1.7
+     * @hide 1.7
+     */
     @Override
     public Set<SocketOption<?>> supportedOptions() {
         // This method was added for interoperability with Java 7, where it is abstract. It is
diff --git a/luni/src/main/java/java/text/BreakIterator.java b/luni/src/main/java/java/text/BreakIterator.java
index b14647c..81545b2 100644
--- a/luni/src/main/java/java/text/BreakIterator.java
+++ b/luni/src/main/java/java/text/BreakIterator.java
@@ -268,13 +268,9 @@
     /**
      * Returns a new instance of {@code BreakIterator} to iterate over
      * characters using the given locale.
-     *
-     * @param where
-     *            the given locale.
-     * @return a new instance of {@code BreakIterator} using the given locale.
      */
-    public static BreakIterator getCharacterInstance(Locale where) {
-        return new RuleBasedBreakIterator(NativeBreakIterator.getCharacterInstance(where));
+    public static BreakIterator getCharacterInstance(Locale locale) {
+        return new RuleBasedBreakIterator(NativeBreakIterator.getCharacterInstance(locale));
     }
 
     /**
@@ -290,14 +286,9 @@
     /**
      * Returns a new instance of {@code BreakIterator} to iterate over
      * line breaks using the given locale.
-     *
-     * @param where
-     *            the given locale.
-     * @return a new instance of {@code BreakIterator} using the given locale.
-     * @throws NullPointerException if {@code where} is {@code null}.
      */
-    public static BreakIterator getLineInstance(Locale where) {
-        return new RuleBasedBreakIterator(NativeBreakIterator.getLineInstance(where));
+    public static BreakIterator getLineInstance(Locale locale) {
+        return new RuleBasedBreakIterator(NativeBreakIterator.getLineInstance(locale));
     }
 
     /**
@@ -313,14 +304,9 @@
     /**
      * Returns a new instance of {@code BreakIterator} to iterate over
      * sentence-breaks using the given locale.
-     *
-     * @param where
-     *            the given locale.
-     * @return a new instance of {@code BreakIterator} using the given locale.
-     * @throws NullPointerException if {@code where} is {@code null}.
      */
-    public static BreakIterator getSentenceInstance(Locale where) {
-        return new RuleBasedBreakIterator(NativeBreakIterator.getSentenceInstance(where));
+    public static BreakIterator getSentenceInstance(Locale locale) {
+        return new RuleBasedBreakIterator(NativeBreakIterator.getSentenceInstance(locale));
     }
 
     /**
@@ -336,14 +322,9 @@
     /**
      * Returns a new instance of {@code BreakIterator} to iterate over
      * word-breaks using the given locale.
-     *
-     * @param where
-     *            the given locale.
-     * @return a new instance of {@code BreakIterator} using the given locale.
-     * @throws NullPointerException if {@code where} is {@code null}.
      */
-    public static BreakIterator getWordInstance(Locale where) {
-        return new RuleBasedBreakIterator(NativeBreakIterator.getWordInstance(where));
+    public static BreakIterator getWordInstance(Locale locale) {
+        return new RuleBasedBreakIterator(NativeBreakIterator.getWordInstance(locale));
     }
 
     /**
diff --git a/luni/src/main/java/java/util/Currency.java b/luni/src/main/java/java/util/Currency.java
index 333ebc4..0dea411 100644
--- a/luni/src/main/java/java/util/Currency.java
+++ b/luni/src/main/java/java/util/Currency.java
@@ -35,7 +35,7 @@
 
     private Currency(String currencyCode) {
         this.currencyCode = currencyCode;
-        String symbol = ICU.getCurrencySymbol(Locale.US.toString(), currencyCode);
+        String symbol = ICU.getCurrencySymbol(Locale.US, currencyCode);
         if (symbol == null) {
             throw new IllegalArgumentException("Unsupported ISO 4217 currency code: " +
                     currencyCode);
@@ -123,7 +123,7 @@
      * @since 1.7
      */
     public String getDisplayName(Locale locale) {
-        return ICU.getCurrencyDisplayName(locale.toString(), currencyCode);
+        return ICU.getCurrencyDisplayName(locale, currencyCode);
     }
 
     /**
@@ -131,6 +131,7 @@
      * zero is returned.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public int getNumericCode() {
         return ICU.getCurrencyNumericCode(currencyCode);
@@ -167,7 +168,7 @@
         }
 
         // Try ICU, and fall back to the currency code if ICU has nothing.
-        String symbol = ICU.getCurrencySymbol(locale.toString(), currencyCode);
+        String symbol = ICU.getCurrencySymbol(locale, currencyCode);
         return symbol != null ? symbol : currencyCode;
     }
 
diff --git a/luni/src/main/java/java/util/IllformedLocaleException.java b/luni/src/main/java/java/util/IllformedLocaleException.java
index 3dec1cd..ff844f7 100644
--- a/luni/src/main/java/java/util/IllformedLocaleException.java
+++ b/luni/src/main/java/java/util/IllformedLocaleException.java
@@ -22,6 +22,7 @@
  * See {@link Locale} and {@link Locale.Builder}.
  *
  * @since 1.7
+ * @hide 1.7
  */
 public class IllformedLocaleException extends RuntimeException {
 
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index 17eb26c..7c5ce5a 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -254,6 +254,7 @@
      * See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public static final char PRIVATE_USE_EXTENSION = 'x';
 
@@ -264,6 +265,7 @@
      * See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public static final char UNICODE_LOCALE_EXTENSION = 'u';
 
@@ -295,6 +297,7 @@
      * the structured state (keywords and attributes) specified therein.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public static final class Builder {
         private String language;
@@ -779,11 +782,13 @@
     /**
      * Returns a locale for a given BCP-47 language tag. This method is more
      * lenient than {@link Builder#setLanguageTag}. For a given language tag, parsing
-     * will proceed upto the first malformed subtag. All subsequent tags are discarded.
+     * will proceed up to the first malformed subtag. All subsequent tags are discarded.
+     * Note that language tags use {@code -} rather than {@code _}, for example {@code en-US}.
      *
      * @throws NullPointerException if {@code languageTag} is {@code null}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public static Locale forLanguageTag(String languageTag) {
         if (languageTag == null) {
@@ -887,17 +892,14 @@
 
         if (hasValidatedFields) {
             Set<String> attribsCopy = new TreeSet<String>(unicodeAttributes);
-            Map<String, String> keywordsCopy = new TreeMap<String, String>(
-                    unicodeKeywords);
-            Map<Character, String> extensionsCopy = new TreeMap<Character, String>(
-                    extensions);
+            Map<String, String> keywordsCopy = new TreeMap<String, String>(unicodeKeywords);
+            Map<Character, String> extensionsCopy = new TreeMap<Character, String>(extensions);
 
             // We need to transform the list of attributes & keywords set on the
             // builder to a unicode locale extension. i.e, if we have any keywords
             // or attributes set, Locale#getExtension('u') should return a well
             // formed extension.
-            addUnicodeExtensionToExtensionsMap(attribsCopy, keywordsCopy,
-                    extensionsCopy);
+            addUnicodeExtensionToExtensionsMap(attribsCopy, keywordsCopy, extensionsCopy);
 
             this.unicodeAttributes = Collections.unmodifiableSet(attribsCopy);
             this.unicodeKeywords = Collections.unmodifiableMap(keywordsCopy);
@@ -1002,10 +1004,16 @@
         if (countryCode.isEmpty()) {
             return "";
         }
-        String result = ICU.getDisplayCountryNative(getIcuLocaleId(), locale.getIcuLocaleId());
+
+        try {
+            Builder.normalizeAndValidateRegion(countryCode);
+        } catch (IllformedLocaleException ex) {
+            return countryCode;
+        }
+
+        String result = ICU.getDisplayCountry(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayCountryNative(getIcuLocaleId(),
-                    Locale.getDefault().getIcuLocaleId());
+            result = ICU.getDisplayCountry(this, Locale.getDefault());
         }
         return result;
     }
@@ -1026,19 +1034,24 @@
             return "";
         }
 
-        // http://b/8049507 --- frameworks/base should use fil_PH instead of tl_PH.
-        // Until then, we're stuck covering their tracks, making it look like they're
-        // using "fil" when they're not.
-        String localeString = toString();
-        if (languageCode.equals("tl")) {
-            localeString = toNewString("fil", countryCode, variantCode, scriptCode,
-                    extensions);
+        // Hacks for backward compatibility.
+        //
+        // Our language tag will contain "und" if the languageCode is invalid
+        // or missing. ICU will then return "langue indéterminée" or the equivalent
+        // display language for the indeterminate language code.
+        //
+        // Sigh... ugh... and what not.
+        try {
+            Builder.normalizeAndValidateLanguage(languageCode);
+        } catch (IllformedLocaleException ex) {
+            return languageCode;
         }
 
-        String result = ICU.getDisplayLanguageNative(localeString, locale.getIcuLocaleId());
+        // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
+        // cover the frameworks' tracks when they were using "tl" instead of "fil".
+        String result = ICU.getDisplayLanguage(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayLanguageNative(localeString,
-                    Locale.getDefault().getIcuLocaleId());
+            result = ICU.getDisplayLanguage(this, Locale.getDefault());
         }
         return result;
     }
@@ -1112,6 +1125,8 @@
      * Returns the full variant name in the default {@code Locale} for the variant code of
      * this {@code Locale}. If there is no matching variant name, the variant code is
      * returned.
+     *
+     * @since 1.7
      */
     public final String getDisplayVariant() {
         return getDisplayVariant(getDefault());
@@ -1121,15 +1136,31 @@
      * Returns the full variant name in the specified {@code Locale} for the variant code
      * of this {@code Locale}. If there is no matching variant name, the variant code is
      * returned.
+     *
+     * @since 1.7
      */
     public String getDisplayVariant(Locale locale) {
-        if (variantCode.length() == 0) {
+        if (variantCode.isEmpty()) {
+            return "";
+        }
+
+        try {
+            Builder.normalizeAndValidateVariant(variantCode);
+        } catch (IllformedLocaleException ilfe) {
             return variantCode;
         }
-        String result = ICU.getDisplayVariantNative(getIcuLocaleId(), locale.getIcuLocaleId());
+
+        String result = ICU.getDisplayVariant(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayVariantNative(getIcuLocaleId(),
-                    Locale.getDefault().getIcuLocaleId());
+            result = ICU.getDisplayVariant(this, Locale.getDefault());
+        }
+
+        // The "old style" locale constructors allow us to pass in variants that aren't
+        // valid BCP-47 variant subtags. When that happens, toLanguageTag will not emit
+        // them. Note that we know variantCode.length() > 0 due to the isEmpty check at
+        // the beginning of this function.
+        if (result.isEmpty()) {
+            return variantCode;
         }
         return result;
     }
@@ -1140,7 +1171,7 @@
      * @throws MissingResourceException if there's no 3-letter country code for this locale.
      */
     public String getISO3Country() {
-        String code = ICU.getISO3CountryNative(getIcuLocaleId());
+        String code = ICU.getISO3Country(this);
         if (!countryCode.isEmpty() && code.isEmpty()) {
             throw new MissingResourceException("No 3-letter country code for locale: " + this, "FormatData_" + this, "ShortCountry");
         }
@@ -1153,7 +1184,15 @@
      * @throws MissingResourceException if there's no 3-letter language code for this locale.
      */
     public String getISO3Language() {
-        String code = ICU.getISO3LanguageNative(getIcuLocaleId());
+        // For backward compatibility, we must return "" for an empty language
+        // code and not "und" which is the accurate ISO-639-3 code for an
+        // undetermined language.
+        if (languageCode.isEmpty()) {
+            return "";
+        }
+
+        String code = ICU.getISO3Language(this);
+
         if (!languageCode.isEmpty() && code.isEmpty()) {
             throw new MissingResourceException("No 3-letter language code for locale: " + this, "FormatData_" + this, "ShortLanguage");
         }
@@ -1200,6 +1239,7 @@
      * specification.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String getScript() {
         return scriptCode;
@@ -1209,6 +1249,7 @@
      * Equivalent to {@code getDisplayScript(Locale.getDefault()))}
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String getDisplayScript() {
         return getDisplayScript(getDefault());
@@ -1220,16 +1261,16 @@
      * {@link #getScript()}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String getDisplayScript(Locale locale) {
         if (scriptCode.isEmpty()) {
             return "";
         }
 
-        String result = ICU.getDisplayScriptNative(getIcuLocaleId(), locale.getIcuLocaleId());
+        String result = ICU.getDisplayScript(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayScriptNative(getIcuLocaleId(),
-                    Locale.getDefault().getIcuLocaleId());
+            result = ICU.getDisplayScript(this, Locale.getDefault());
         }
 
         return result;
@@ -1250,12 +1291,13 @@
      * where they will appear after a subtag whose value is {@code "lvariant"}.
      *
      * It's also important to note that the BCP-47 tag is well formed in the sense
-     * that it is unambiguously parsable into its specified components. We do not
+     * that it is unambiguously parseable into its specified components. We do not
      * require that any of the components are registered with the applicable registries.
      * For example, we do not require scripts to be a registered ISO 15924 scripts or
      * languages to appear in the ISO-639-2 code list.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String toLanguageTag() {
         if (cachedLanguageTag == null) {
@@ -1471,6 +1513,7 @@
      *     the IETF BCP-47 specification</a> (Section 2.2.6) for details.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public Set<Character> getExtensionKeys() {
         return extensions.keySet();
@@ -1485,6 +1528,7 @@
      * {@link #getUnicodeLocaleKeys()}  and {@link #getUnicodeLocaleType}.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String getExtension(char extensionKey) {
         return extensions.get(extensionKey);
@@ -1497,6 +1541,7 @@
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
      * @since 1.7
+     * @hide 1.7
      */
     public String getUnicodeLocaleType(String keyWord) {
         return unicodeKeywords.get(keyWord);
@@ -1509,6 +1554,7 @@
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
      * @since 1.7
+     * @hide 1.7
      */
     public Set<String> getUnicodeLocaleAttributes() {
         return unicodeAttributes;
@@ -1521,6 +1567,7 @@
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
      * @since 1.7
+     * @hide 1.7
      */
     public Set<String> getUnicodeLocaleKeys() {
         return unicodeKeywords.keySet();
@@ -1545,8 +1592,9 @@
         if (locale == null) {
             throw new NullPointerException("locale == null");
         }
+        String languageTag = locale.toLanguageTag();
         defaultLocale = locale;
-        ICU.setDefaultLocale(ICU.localeIdFromLocale(locale));
+        ICU.setDefaultLocale(languageTag);
     }
 
     /**
@@ -1564,20 +1612,12 @@
     public final String toString() {
         String result = cachedToStringResult;
         if (result == null) {
-            result = cachedToStringResult = toNewString(languageCode, countryCode,
-                    variantCode, scriptCode, extensions);
+            result = cachedToStringResult = toNewString(languageCode, countryCode, variantCode,
+                                                        scriptCode, extensions);
         }
         return result;
     }
 
-    private String getIcuLocaleId() {
-        if (cachedIcuLocaleId == null) {
-            cachedIcuLocaleId = ICU.localeIdFromLocale(this);
-        }
-
-        return cachedIcuLocaleId;
-    }
-
     private static String toNewString(String languageCode, String countryCode,
             String variantCode, String scriptCode, Map<Character, String> extensions) {
         // The string form of a locale that only has a variant is the empty string.
@@ -1592,8 +1632,7 @@
         StringBuilder result = new StringBuilder(11);
         result.append(languageCode);
 
-        final boolean hasScriptOrExtensions = !scriptCode.isEmpty() ||
-                !extensions.isEmpty();
+        final boolean hasScriptOrExtensions = !scriptCode.isEmpty() || !extensions.isEmpty();
 
         if (!countryCode.isEmpty() || !variantCode.isEmpty() || hasScriptOrExtensions) {
             result.append('_');
@@ -1799,8 +1838,7 @@
         return true;
     }
 
-    private static boolean isValidBcp47Alpha(String string,
-            int lowerBound, int upperBound) {
+    private static boolean isValidBcp47Alpha(String string, int lowerBound, int upperBound) {
         final int length = string.length();
         if (length < lowerBound || length > upperBound) {
             return false;
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index b38d6a5..eae9497 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -57,6 +57,7 @@
  * the {@code ConcurrentLinkedDeque} in another thread.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  * @author Martin Buchholz
  * @param <E> the type of elements held in this collection
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 9448616..2cbee65 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -127,6 +127,7 @@
  * or internal resources have been exhausted.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public class ForkJoinPool extends AbstractExecutorService {
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
index c6bc6de..2936be8 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -175,6 +175,7 @@
  * execution. Serialization is not relied on during execution itself.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index ae28700..05c28a0 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -18,6 +18,7 @@
  * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public class ForkJoinWorkerThread extends Thread {
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index a041fb1..43d9fb7 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -50,6 +50,7 @@
  * the {@code LinkedTransferQueue} in another thread.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this collection
  */
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
index a97d187..4f9c76c 100644
--- a/luni/src/main/java/java/util/concurrent/Phaser.java
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -227,6 +227,7 @@
  * of participants.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public class Phaser {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
index e3a6340..a16388c 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveAction.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
@@ -131,6 +131,7 @@
  * }}</pre>
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public abstract class RecursiveAction extends ForkJoinTask<Void> {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
index 80baa52..45adeee 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -34,6 +34,7 @@
  * sequentially solve rather than subdividing.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 483981d..f450a0f 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -690,6 +690,7 @@
      * @param value if {@code true}, remove on cancellation, else don't
      * @see #getRemoveOnCancelPolicy
      * @since 1.7
+     * @hide 1.7
      */
     public void setRemoveOnCancelPolicy(boolean value) {
         removeOnCancel = value;
@@ -704,6 +705,7 @@
      *         from the queue
      * @see #setRemoveOnCancelPolicy
      * @since 1.7
+     * @hide 1.7
      */
     public boolean getRemoveOnCancelPolicy() {
         return removeOnCancel;
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index 5baf75f..bd618ca 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -30,6 +30,7 @@
  * generation methods.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  */
 public class ThreadLocalRandom extends Random {
diff --git a/luni/src/main/java/java/util/concurrent/TransferQueue.java b/luni/src/main/java/java/util/concurrent/TransferQueue.java
index 4c2be6f..debcedc 100644
--- a/luni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -33,6 +33,7 @@
  * and {@code transfer} are effectively synonymous.
  *
  * @since 1.7
+ * @hide 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this collection
  */
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 37aa9d0..f130fb0 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -1255,6 +1255,7 @@
      *         current thread, and {@code false} if the current thread
      *         is at the head of the queue or the queue is empty
      * @since 1.7
+     * @hide 1.7
      */
     public final boolean hasQueuedPredecessors() {
         // The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index e711da5..1c766e7 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -1485,6 +1485,7 @@
      *         current thread, and {@code false} if the current thread
      *         is at the head of the queue or the queue is empty
      * @since 1.7
+     * @hide 1.7
      */
     public final boolean hasQueuedPredecessors() {
         // The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/zip/ZipFile.java b/luni/src/main/java/java/util/zip/ZipFile.java
index 877e9ee..9894152 100644
--- a/luni/src/main/java/java/util/zip/ZipFile.java
+++ b/luni/src/main/java/java/util/zip/ZipFile.java
@@ -132,6 +132,7 @@
      * @throws ZipException if a zip error occurs.
      * @throws IOException if an {@code IOException} occurs.
      * @since 1.7
+     * @hide 1.7
      */
     public ZipFile(File file, Charset charset) throws ZipException, IOException {
         this(file, OPEN_READ, charset);
@@ -178,6 +179,7 @@
      *
      * @throws IOException if an {@code IOException} occurs.
      * @since 1.7
+     * @hide 1.7
      */
     public ZipFile(File file, int mode, Charset charset) throws IOException {
         filename = file.getPath();
diff --git a/luni/src/main/java/java/util/zip/ZipInputStream.java b/luni/src/main/java/java/util/zip/ZipInputStream.java
index 402cd33..f1a5208 100644
--- a/luni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipInputStream.java
@@ -108,6 +108,7 @@
      * by the zip file then {@code charset} is used to decode them.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public ZipInputStream(InputStream stream, Charset charset) {
         super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
diff --git a/luni/src/main/java/java/util/zip/ZipOutputStream.java b/luni/src/main/java/java/util/zip/ZipOutputStream.java
index 77b00c9..aeb77e9 100644
--- a/luni/src/main/java/java/util/zip/ZipOutputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipOutputStream.java
@@ -114,6 +114,7 @@
      * comments.
      *
      * @since 1.7
+     * @hide 1.7
      */
     public ZipOutputStream(OutputStream os, Charset charset) {
         super(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
diff --git a/luni/src/main/java/javax/net/ssl/SSLEngine.java b/luni/src/main/java/javax/net/ssl/SSLEngine.java
index b55acd4..d938642 100644
--- a/luni/src/main/java/javax/net/ssl/SSLEngine.java
+++ b/luni/src/main/java/javax/net/ssl/SSLEngine.java
@@ -783,6 +783,7 @@
      *
      * @return the SSL session for this engine instance.
      * @since 1.7
+     * @hide 1.7
      */
     public SSLSession getHandshakeSession() {
         throw new UnsupportedOperationException();
diff --git a/luni/src/main/java/javax/net/ssl/SSLParameters.java b/luni/src/main/java/javax/net/ssl/SSLParameters.java
index 93e766f..d049038 100644
--- a/luni/src/main/java/javax/net/ssl/SSLParameters.java
+++ b/luni/src/main/java/javax/net/ssl/SSLParameters.java
@@ -146,6 +146,7 @@
      *
      * @see #setEndpointIdentificationAlgorithm(String)
      * @since 1.7
+     * @hide 1.7
      */
     public String getEndpointIdentificationAlgorithm() {
         return endpointIdentificationAlgorithm;
@@ -157,6 +158,7 @@
      *
      * @see #getEndpointIdentificationAlgorithm()
      * @since 1.7
+     * @hide 1.7
      */
     public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) {
         this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
diff --git a/luni/src/main/java/javax/net/ssl/SSLSocket.java b/luni/src/main/java/javax/net/ssl/SSLSocket.java
index 148f3cf..dd89e90 100644
--- a/luni/src/main/java/javax/net/ssl/SSLSocket.java
+++ b/luni/src/main/java/javax/net/ssl/SSLSocket.java
@@ -895,6 +895,7 @@
      *
      * @return the session object.
      * @since 1.7
+     * @hide 1.7
      */
     public SSLSession getHandshakeSession() {
         throw new UnsupportedOperationException();
diff --git a/luni/src/main/java/javax/net/ssl/X509ExtendedTrustManager.java b/luni/src/main/java/javax/net/ssl/X509ExtendedTrustManager.java
index 2af1c11..61ab169 100644
--- a/luni/src/main/java/javax/net/ssl/X509ExtendedTrustManager.java
+++ b/luni/src/main/java/javax/net/ssl/X509ExtendedTrustManager.java
@@ -27,6 +27,7 @@
  *
  * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
  * @since 1.7
+ * @hide 1.7
  */
 public abstract class X509ExtendedTrustManager implements X509TrustManager {
     /**
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index cf04ff9..407ebfd 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -239,70 +239,6 @@
         true /* has validated fields */);
   }
 
-  /**
-   * Builds an ICU locale ID from the given locale. The format is very
-   * straightforward. It is a series of subtags in BCP 47 order
-   * {@code lang[_script][_country][_variant]} followed by the keyword
-   * separator {@code @} followed by a list of keywords. Each keyword is
-   * a key value pair, and appear in the form {@code k1=v1;k2=v2;...}.
-   *
-   * In this use case, each key is an extension identifier, and each value
-   * is the value of the extension.
-   */
-  public static String localeIdFromLocale(Locale l) {
-      StringBuilder b = new StringBuilder(16);
-      b.append(l.getLanguage());
-
-      final boolean hasScript = !l.getScript().isEmpty();
-      final boolean hasCountry = !l.getCountry().isEmpty();
-      final boolean hasVariant = !l.getVariant().isEmpty();
-
-      if (hasScript || hasCountry || hasVariant) {
-          b.append('_');
-          if (hasScript) {
-              b.append(l.getScript());
-              if (hasCountry || hasVariant) {
-                  b.append('_');
-              }
-          }
-
-          if (hasCountry) {
-              b.append(l.getCountry());
-              if (hasVariant) {
-                  b.append('_');
-              }
-          }
-
-          b.append(l.getVariant());
-      }
-
-      if (!l.getExtensionKeys().isEmpty()) {
-        b.append('@');
-        // The private use extension ('x') must show up last in the list
-        // so we cache its value here and append it right at the end.
-        String privateUseExtensionValue = null;
-        for (char c : l.getExtensionKeys()) {
-          if (c == Locale.PRIVATE_USE_EXTENSION) {
-            privateUseExtensionValue = l.getExtension(Locale.PRIVATE_USE_EXTENSION);
-          } else {
-            b.append(c);
-            b.append('=');
-            b.append(l.getExtension(c));
-            b.append(';');
-          }
-        }
-
-        if (privateUseExtensionValue != null) {
-          b.append(Locale.PRIVATE_USE_EXTENSION);
-          b.append('=');
-          b.append(privateUseExtensionValue);
-          b.append(';');
-        }
-      }
-
-      return b.toString();
-  }
-
   public static Locale[] localesFromStrings(String[] localeNames) {
     // We need to remove duplicates caused by the conversion of "he" to "iw", et cetera.
     // Java needs the obsolete code, ICU needs the modern code, but we let ICU know about
@@ -349,19 +285,20 @@
     return localesFromStrings(getAvailableNumberFormatLocalesNative());
   }
 
-  public static String getBestDateTimePattern(String skeleton, String localeName) {
-    String key = skeleton + "\t" + localeName;
+  public static String getBestDateTimePattern(String skeleton, Locale locale) {
+    String languageTag = locale.toLanguageTag();
+    String key = skeleton + "\t" + languageTag;
     synchronized (CACHED_PATTERNS) {
       String pattern = CACHED_PATTERNS.get(key);
       if (pattern == null) {
-        pattern = getBestDateTimePatternNative(skeleton, localeName);
+        pattern = getBestDateTimePatternNative(skeleton, languageTag);
         CACHED_PATTERNS.put(key, pattern);
       }
       return pattern;
     }
   }
 
-  private static native String getBestDateTimePatternNative(String skeleton, String localeName);
+  private static native String getBestDateTimePatternNative(String skeleton, String languageTag);
 
   public static char[] getDateFormatOrder(String pattern) {
     char[] result = new char[3];
@@ -421,8 +358,17 @@
 
   // --- Case mapping.
 
-  public static native String toLowerCase(String s, String localeName);
-  public static native String toUpperCase(String s, String localeName);
+  public static String toLowerCase(String s, Locale locale) {
+    return toLowerCase(s, locale.toLanguageTag());
+  }
+
+  private static native String toLowerCase(String s, String languageTag);
+
+  public static String toUpperCase(String s, Locale locale) {
+    return toUpperCase(s, locale.toLanguageTag());
+  }
+
+  private static native String toUpperCase(String s, String languageTag);
 
   // --- Errors.
 
@@ -448,18 +394,57 @@
 
   public static native String[] getAvailableCurrencyCodes();
   public static native String getCurrencyCode(String countryCode);
-  public static native String getCurrencyDisplayName(String locale, String currencyCode);
+
+  public static String getCurrencyDisplayName(Locale locale, String currencyCode) {
+    return getCurrencyDisplayName(locale.toLanguageTag(), currencyCode);
+  }
+
+  private static native String getCurrencyDisplayName(String languageTag, String currencyCode);
+
   public static native int getCurrencyFractionDigits(String currencyCode);
   public static native int getCurrencyNumericCode(String currencyCode);
-  public static native String getCurrencySymbol(String locale, String currencyCode);
 
-  public static native String getDisplayCountryNative(String countryCode, String locale);
-  public static native String getDisplayLanguageNative(String languageCode, String locale);
-  public static native String getDisplayVariantNative(String variantCode, String locale);
-  public static native String getDisplayScriptNative(String variantCode, String locale);
+  public static String getCurrencySymbol(Locale locale, String currencyCode) {
+    return getCurrencySymbol(locale.toLanguageTag(), currencyCode);
+  }
 
-  public static native String getISO3CountryNative(String locale);
-  public static native String getISO3LanguageNative(String locale);
+  private static native String getCurrencySymbol(String languageTag, String currencyCode);
+
+  public static String getDisplayCountry(Locale targetLocale, Locale locale) {
+    return getDisplayCountryNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+  }
+
+  private static native String getDisplayCountryNative(String targetLanguageTag, String languageTag);
+
+  public static String getDisplayLanguage(Locale targetLocale, Locale locale) {
+    return getDisplayLanguageNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+  }
+
+  private static native String getDisplayLanguageNative(String targetLanguageTag, String languageTag);
+
+  public static String getDisplayVariant(Locale targetLocale, Locale locale) {
+    return getDisplayVariantNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+  }
+
+  private static native String getDisplayVariantNative(String targetLanguageTag, String languageTag);
+
+  public static String getDisplayScript(Locale targetLocale, Locale locale) {
+    return getDisplayScriptNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+  }
+
+  private static native String getDisplayScriptNative(String targetLanguageTag, String languageTag);
+
+  public static String getISO3Country(Locale locale) {
+    return getISO3CountryNative(locale.toLanguageTag());
+  }
+
+  private static native String getISO3CountryNative(String languageTag);
+
+  public static String getISO3Language(Locale locale) {
+    return getISO3LanguageNative(locale.toLanguageTag());
+  }
+
+  private static native String getISO3LanguageNative(String languageTag);
 
   public static native String addLikelySubtags(String locale);
   public static native String getScript(String locale);
@@ -471,6 +456,6 @@
 
   static native boolean initLocaleDataNative(String locale, LocaleData result);
 
-  public static native void setDefaultLocale(String locale);
+  public static native void setDefaultLocale(String languageTag);
   public static native String getDefaultLocale();
 }
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index 49228b3..845ba32 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -176,8 +176,8 @@
         }
 
         // Get the "h:mm a" and "HH:mm" 12- and 24-hour time format strings.
-        localeData.timeFormat12 = ICU.getBestDateTimePattern("hm", locale.toString());
-        localeData.timeFormat24 = ICU.getBestDateTimePattern("Hm", locale.toString());
+        localeData.timeFormat12 = ICU.getBestDateTimePattern("hm", locale);
+        localeData.timeFormat24 = ICU.getBestDateTimePattern("Hm", locale);
 
         // Fix up a couple of patterns.
         if (localeData.fullTimeFormat != null) {
diff --git a/luni/src/main/java/libcore/icu/NativeBreakIterator.java b/luni/src/main/java/libcore/icu/NativeBreakIterator.java
index 7168d96..992aac2 100644
--- a/luni/src/main/java/libcore/icu/NativeBreakIterator.java
+++ b/luni/src/main/java/libcore/icu/NativeBreakIterator.java
@@ -138,23 +138,23 @@
     }
 
     public int preceding(int offset) {
-      return precedingImpl(this.address, this.string, offset);
+        return precedingImpl(this.address, this.string, offset);
     }
 
-    public static NativeBreakIterator getCharacterInstance(Locale where) {
-        return new NativeBreakIterator(getCharacterInstanceImpl(where.toString()), BI_CHAR_INSTANCE);
+    public static NativeBreakIterator getCharacterInstance(Locale locale) {
+        return new NativeBreakIterator(getCharacterInstanceImpl(locale.toLanguageTag()), BI_CHAR_INSTANCE);
     }
 
-    public static NativeBreakIterator getLineInstance(Locale where) {
-        return new NativeBreakIterator(getLineInstanceImpl(where.toString()), BI_LINE_INSTANCE);
+    public static NativeBreakIterator getLineInstance(Locale locale) {
+        return new NativeBreakIterator(getLineInstanceImpl(locale.toLanguageTag()), BI_LINE_INSTANCE);
     }
 
-    public static NativeBreakIterator getSentenceInstance(Locale where) {
-        return new NativeBreakIterator(getSentenceInstanceImpl(where.toString()), BI_SENT_INSTANCE);
+    public static NativeBreakIterator getSentenceInstance(Locale locale) {
+        return new NativeBreakIterator(getSentenceInstanceImpl(locale.toLanguageTag()), BI_SENT_INSTANCE);
     }
 
-    public static NativeBreakIterator getWordInstance(Locale where) {
-        return new NativeBreakIterator(getWordInstanceImpl(where.toString()), BI_WORD_INSTANCE);
+    public static NativeBreakIterator getWordInstance(Locale locale) {
+        return new NativeBreakIterator(getWordInstanceImpl(locale.toLanguageTag()), BI_WORD_INSTANCE);
     }
 
     private static native long getCharacterInstanceImpl(String locale);
diff --git a/luni/src/main/java/libcore/icu/NativeCollation.java b/luni/src/main/java/libcore/icu/NativeCollation.java
index 64e0278..b4b4f46 100644
--- a/luni/src/main/java/libcore/icu/NativeCollation.java
+++ b/luni/src/main/java/libcore/icu/NativeCollation.java
@@ -10,6 +10,8 @@
 
 package libcore.icu;
 
+import java.util.Locale;
+
 /**
 * Package static class for declaring all native methods for collation use.
 * @author syn wee quek
@@ -26,7 +28,10 @@
     public static native long getCollationElementIterator(long address, String source);
     public static native String getRules(long address);
     public static native byte[] getSortKey(long address, String source);
-    public static native long openCollator(String locale);
+    public static long openCollator(Locale locale) {
+      return openCollator(locale.toLanguageTag());
+    }
+    private static native long openCollator(String languageTag);
     public static native long openCollatorFromRules(String rules, int normalizationMode, int collationStrength);
     public static native long safeClone(long address);
     public static native void setAttribute(long address, int type, int value);
diff --git a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
index 3ea942d..b23013b 100644
--- a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
+++ b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
@@ -52,7 +52,7 @@
     }
 
     public RuleBasedCollatorICU(Locale locale) {
-        address = NativeCollation.openCollator(locale.toString());
+        address = NativeCollation.openCollator(locale);
     }
 
     private RuleBasedCollatorICU(long address) {
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index c6f3950..7ce2168 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -28,10 +28,6 @@
 #include "unicode/uloc.h"
 #include "unicode/ustring.h"
 
-Locale getLocale(JNIEnv* env, jstring localeName) {
-  return Locale::createFromName(ScopedUtfChars(env, localeName).c_str());
-}
-
 jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration* se) {
   if (maybeThrowIcuException(env, provider, status)) {
     return NULL;
diff --git a/luni/src/main/native/IcuUtilities.h b/luni/src/main/native/IcuUtilities.h
index ffcfcda..737379e 100644
--- a/luni/src/main/native/IcuUtilities.h
+++ b/luni/src/main/native/IcuUtilities.h
@@ -23,9 +23,7 @@
 #include "jni.h"
 #include "ustrenum.h" // For UStringEnumeration.
 #include "unicode/utypes.h" // For UErrorCode.
-#include "unicode/locid.h" // For Locale.
 
-extern Locale getLocale(JNIEnv* env, jstring localeName);
 extern jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration*);
 bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error);
 
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 13a0b1c..87ebc21 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -254,7 +254,7 @@
 #if defined(IFA_F_TEMPORARY)
     initConstant(env, c, "IFA_F_TEMPORARY", IFA_F_TEMPORARY);
 #endif
-#if defined(IDA_F_TENTATIVE)
+#if defined(IFA_F_TENTATIVE)
     initConstant(env, c, "IFA_F_TENTATIVE", IFA_F_TENTATIVE);
 #endif
     initConstant(env, c, "IFF_ALLMULTI", IFF_ALLMULTI);
@@ -390,19 +390,15 @@
     initConstant(env, c, "PROT_READ", PROT_READ);
     initConstant(env, c, "PROT_WRITE", PROT_WRITE);
     initConstant(env, c, "R_OK", R_OK);
-#if defined(RT_SCOPE_HOST)
+// NOTE: The RT_* constants are not preprocessor defines, they're enum
+// members. The best we can do (barring UAPI / kernel version checks) is
+// to hope they exist on all host linuxes we're building on. These
+// constants have been around since 2.6.35 at least, so we should be ok.
+#if !defined(__APPLE__)
     initConstant(env, c, "RT_SCOPE_HOST", RT_SCOPE_HOST);
-#endif
-#if defined(RT_SCOPE_LINK)
     initConstant(env, c, "RT_SCOPE_LINK", RT_SCOPE_LINK);
-#endif
-#if defined(RT_SCOPE_NOWHERE)
     initConstant(env, c, "RT_SCOPE_NOWHERE", RT_SCOPE_NOWHERE);
-#endif
-#if defined(RT_SCOPE_SITE)
     initConstant(env, c, "RT_SCOPE_SITE", RT_SCOPE_SITE);
-#endif
-#if defined(RT_SCOPE_UNIVERSE)
     initConstant(env, c, "RT_SCOPE_UNIVERSE", RT_SCOPE_UNIVERSE);
 #endif
     initConstant(env, c, "SEEK_CUR", SEEK_CUR);
diff --git a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
index bb05193..e0638bd 100644
--- a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
+++ b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
@@ -20,6 +20,7 @@
 #include "JNIHelp.h"
 #include "JniConstants.h"
 #include "JniException.h"
+#include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
 #include "unicode/alphaindex.h"
 #include "unicode/uniset.h"
@@ -28,9 +29,13 @@
   return reinterpret_cast<AlphabeticIndex*>(static_cast<uintptr_t>(peer));
 }
 
-static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) {
   UErrorCode status = U_ZERO_ERROR;
-  AlphabeticIndex* ai = new AlphabeticIndex(getLocale(env, javaLocale), status);
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return 0;
+  }
+  AlphabeticIndex* ai = new AlphabeticIndex(icuLocale.locale(), status);
   if (maybeThrowIcuException(env, "AlphabeticIndex", status)) {
     return 0;
   }
@@ -53,10 +58,14 @@
   maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status);
 }
 
-static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocale) {
+static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) {
   AlphabeticIndex* ai = fromPeer(peer);
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return;
+  }
   UErrorCode status = U_ZERO_ERROR;
-  ai->addLabels(getLocale(env, javaLocale), status);
+  ai->addLabels(icuLocale.locale(), status);
   maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
 }
 
diff --git a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
index 72bc631..a3258c1 100644
--- a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
@@ -18,13 +18,17 @@
 
 #include "IcuUtilities.h"
 #include "JniConstants.h"
+#include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
 #include "UniquePtr.h"
 #include "cutils/log.h"
 #include "unicode/dtitvfmt.h"
 
 static jlong DateIntervalFormat_createDateIntervalFormat(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName, jstring javaTzName) {
-  Locale locale = getLocale(env, javaLocaleName);
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return 0;
+  }
 
   ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
   if (!skeletonHolder.valid()) {
@@ -32,7 +36,7 @@
   }
 
   UErrorCode status = U_ZERO_ERROR;
-  DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), locale, status));
+  DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), icuLocale.locale(), status));
   if (maybeThrowIcuException(env, "DateIntervalFormat::createInstance", status)) {
     return 0;
   }
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 7b1aac1..8cf58bc 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -21,6 +21,7 @@
 #include "JniConstants.h"
 #include "JniException.h"
 #include "ScopedFd.h"
+#include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
@@ -96,30 +97,30 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
 };
 
-static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocale) {
+static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocaleName) {
     UErrorCode status = U_ZERO_ERROR;
-    ScopedUtfChars localeID(env, javaLocale);
+    ScopedUtfChars localeID(env, javaLocaleName);
     char maximizedLocaleID[ULOC_FULLNAME_CAPACITY];
     uloc_addLikelySubtags(localeID.c_str(), maximizedLocaleID, sizeof(maximizedLocaleID), &status);
     if (U_FAILURE(status)) {
-        return javaLocale;
+        return javaLocaleName;
     }
     return env->NewStringUTF(maximizedLocaleID);
 }
 
-static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocale) {
-    UErrorCode status = U_ZERO_ERROR;
-    ScopedUtfChars localeID(env, javaLocale);
-    char script[ULOC_SCRIPT_CAPACITY];
-    uloc_getScript(localeID.c_str(), script, sizeof(script), &status);
-    if (U_FAILURE(status)) {
-        return NULL;
-    }
-    return env->NewStringUTF(script);
+static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocaleName) {
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  return env->NewStringUTF(icuLocale.locale().getScript());
 }
 
 static jstring ICU_localeForLanguageTag(JNIEnv* env, jclass, jstring languageTag, jboolean strict) {
     ScopedUtfChars languageTagChars(env, languageTag);
+    if (languageTagChars.c_str() == NULL) {
+      return NULL;
+    }
 
     // Naively assume that in the average case, the size of
     // the normalized language tag will be very nearly the same as the
@@ -158,8 +159,7 @@
     // NOTE: The cast is safe because parsedLength can never be negative thanks
     // to the check above. ICU does not document any negative return values for
     // that field, but check for it anyway.
-    if ((strict == JNI_TRUE) &&
-        (static_cast<uint32_t>(parsedLength) != languageTagChars.size())) {
+    if ((strict == JNI_TRUE) && (static_cast<uint32_t>(parsedLength) != languageTagChars.size())) {
         return NULL;
     }
 
@@ -228,9 +228,9 @@
     return (charCount == 0) ? env->NewStringUTF("XXX") : env->NewString(chars, charCount);
 }
 
-static jstring getCurrencyName(JNIEnv* env, jstring javaLocaleName, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
-  ScopedUtfChars localeName(env, javaLocaleName);
-  if (localeName.c_str() == NULL) {
+static jstring getCurrencyName(JNIEnv* env, jstring javaLanguageTag, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
+  ScopedUtfChars languageTag(env, javaLanguageTag);
+  if (languageTag.c_str() == NULL) {
     return NULL;
   }
   ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
@@ -241,7 +241,7 @@
   UErrorCode status = U_ZERO_ERROR;
   UBool isChoiceFormat = false;
   int32_t charCount;
-  const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), localeName.c_str(),
+  const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), languageTag.c_str(),
                                      nameStyle, &isChoiceFormat, &charCount, &status);
   if (status == U_USING_DEFAULT_WARNING) {
     if (nameStyle == UCURR_SYMBOL_NAME) {
@@ -260,54 +260,88 @@
   return (charCount == 0) ? NULL : env->NewString(chars, charCount);
 }
 
-static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaCurrencyCode) {
-  return getCurrencyName(env, javaLocaleName, javaCurrencyCode, UCURR_LONG_NAME);
+static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
+  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_LONG_NAME);
 }
 
-static jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaCurrencyCode) {
-  return getCurrencyName(env, javaLocaleName, javaCurrencyCode, UCURR_SYMBOL_NAME);
+static jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
+  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_SYMBOL_NAME);
 }
 
-static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    Locale targetLoc = getLocale(env, targetLocale);
-    UnicodeString str;
-    targetLoc.getDisplayCountry(loc, str);
-    return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+  if (!icuTargetLocale.valid()) {
+    return NULL;
+  }
+
+  UnicodeString str;
+  icuTargetLocale.locale().getDisplayCountry(icuLocale.locale(), str);
+  return env->NewString(str.getBuffer(), str.length());
 }
 
-static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    Locale targetLoc = getLocale(env, targetLocale);
-    UnicodeString str;
-    targetLoc.getDisplayLanguage(loc, str);
-    return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+  if (!icuTargetLocale.valid()) {
+    return NULL;
+  }
+
+  UnicodeString str;
+  icuTargetLocale.locale().getDisplayLanguage(icuLocale.locale(), str);
+  return env->NewString(str.getBuffer(), str.length());
 }
 
-static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    Locale targetLoc = getLocale(env, targetLocale);
-    UnicodeString str;
-    targetLoc.getDisplayScript(loc, str);
-    return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+  if (!icuTargetLocale.valid()) {
+    return NULL;
+  }
+
+  UnicodeString str;
+  icuTargetLocale.locale().getDisplayScript(icuLocale.locale(), str);
+  return env->NewString(str.getBuffer(), str.length());
 }
 
-static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    Locale targetLoc = getLocale(env, targetLocale);
-    UnicodeString str;
-    targetLoc.getDisplayVariant(loc, str);
-    return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+  if (!icuTargetLocale.valid()) {
+    return NULL;
+  }
+
+  UnicodeString str;
+  icuTargetLocale.locale().getDisplayVariant(icuLocale.locale(), str);
+  return env->NewString(str.getBuffer(), str.length());
 }
 
-static jstring ICU_getISO3CountryNative(JNIEnv* env, jclass, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    return env->NewStringUTF(loc.getISO3Country());
+static jstring ICU_getISO3CountryNative(JNIEnv* env, jclass, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  return env->NewStringUTF(icuLocale.locale().getISO3Country());
 }
 
-static jstring ICU_getISO3LanguageNative(JNIEnv* env, jclass, jstring locale) {
-    Locale loc = getLocale(env, locale);
-    return env->NewStringUTF(loc.getISO3Language());
+static jstring ICU_getISO3LanguageNative(JNIEnv* env, jclass, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+  return env->NewStringUTF(icuLocale.locale().getISO3Language());
 }
 
 static jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
@@ -538,7 +572,10 @@
         return JNI_FALSE; // ICU has a fixed-length limit.
     }
 
-    Locale locale = getLocale(env, javaLocaleName);
+    ScopedIcuLocale icuLocale(env, javaLocaleName);
+    if (!icuLocale.valid()) {
+      return JNI_FALSE;
+    }
 
     // Get the DateTimePatterns.
     UErrorCode status = U_ZERO_ERROR;
@@ -557,7 +594,7 @@
     // Get the "Yesterday", "Today", and "Tomorrow" strings.
     bool foundYesterdayTodayAndTomorrow = false;
     for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
-      if (getYesterdayTodayAndTomorrow(env, localeData, locale, it.Get())) {
+      if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
         foundYesterdayTodayAndTomorrow = true;
         break;
       }
@@ -568,7 +605,7 @@
     }
 
     status = U_ZERO_ERROR;
-    UniquePtr<Calendar> cal(Calendar::createInstance(locale, status));
+    UniquePtr<Calendar> cal(Calendar::createInstance(icuLocale.locale(), status));
     if (U_FAILURE(status)) {
         return JNI_FALSE;
     }
@@ -578,7 +615,7 @@
 
     // Get DateFormatSymbols.
     status = U_ZERO_ERROR;
-    DateFormatSymbols dateFormatSym(locale, status);
+    DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
     if (U_FAILURE(status)) {
         return JNI_FALSE;
     }
@@ -631,8 +668,8 @@
     status = U_ZERO_ERROR;
 
     // For numberPatterns and symbols.
-    setNumberPatterns(env, localeData, locale);
-    setDecimalFormatSymbolsData(env, localeData, locale);
+    setNumberPatterns(env, localeData, icuLocale.locale());
+    setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
 
     jstring countryCode = env->NewStringUTF(Locale::createFromName(localeName.c_str()).getCountry());
     jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
@@ -655,25 +692,33 @@
     return JNI_TRUE;
 }
 
-static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
+static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
   ScopedJavaUnicodeString scopedString(env, javaString);
   if (!scopedString.valid()) {
     return NULL;
   }
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
   UnicodeString& s(scopedString.unicodeString());
   UnicodeString original(s);
-  s.toLower(getLocale(env, localeName));
+  s.toLower(icuLocale.locale());
   return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
 }
 
-static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
+static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
   ScopedJavaUnicodeString scopedString(env, javaString);
   if (!scopedString.valid()) {
     return NULL;
   }
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
   UnicodeString& s(scopedString.unicodeString());
   UnicodeString original(s);
-  s.toUpper(getLocale(env, localeName));
+  s.toUpper(icuLocale.locale());
   return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
 }
 
@@ -708,10 +753,14 @@
   return fromStringEnumeration(env, status, "ucurr_openISOCurrencies", &e);
 }
 
-static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName) {
-  Locale locale = getLocale(env, javaLocaleName);
+static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
+
   UErrorCode status = U_ZERO_ERROR;
-  UniquePtr<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(locale, status));
+  UniquePtr<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
   if (maybeThrowIcuException(env, "DateTimePatternGenerator::createInstance", status)) {
     return NULL;
   }
@@ -728,16 +777,14 @@
   return env->NewString(result.getBuffer(), result.length());
 }
 
-static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLocaleName) {
-  Locale locale = getLocale(env, javaLocaleName);
-  UErrorCode status = U_ZERO_ERROR;
+static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLanguageTag) {
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return;
+  }
 
-  // TODO: Should we check whether locale.isBogus() here ? ICU will
-  // accept bogus locales as the default without complaint. It
-  // shouldn't make a difference in practice, users that set a bogus
-  // locale as the default shouldn't have any realistic expectation that
-  // things like defaults etc. will work correctly.
-  Locale::setDefault(locale, status);
+  UErrorCode status = U_ZERO_ERROR;
+  Locale::setDefault(icuLocale.locale(), status);
   maybeThrowIcuException(env, "Locale::setDefault", status);
 }
 
diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
index 0c8c3c9..ef0c2a9 100644
--- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
+++ b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
@@ -20,6 +20,7 @@
 #include "JNIHelp.h"
 #include "JniConstants.h"
 #include "JniException.h"
+#include "ScopedIcuLocale.h"
 #include "ScopedUtfChars.h"
 #include "unicode/brkiter.h"
 #include "unicode/putil.h"
@@ -107,13 +108,12 @@
 };
 
 #define MAKE_BREAK_ITERATOR_INSTANCE(F) \
-  UErrorCode status = U_ZERO_ERROR; \
-  const ScopedUtfChars localeChars(env, javaLocale); \
-  if (localeChars.c_str() == NULL) { \
+  ScopedIcuLocale icuLocale(env, javaLocaleName); \
+  if (!icuLocale.valid()) { \
     return 0; \
   } \
-  Locale locale(Locale::createFromName(localeChars.c_str())); \
-  BreakIterator* it = F(locale, status); \
+  UErrorCode status = U_ZERO_ERROR; \
+  BreakIterator* it = F(icuLocale.locale(), status); \
   if (maybeThrowIcuException(env, "ubrk_open", status)) { \
     return 0; \
   } \
@@ -143,19 +143,19 @@
   return it->following(offset);
 }
 
-static jlong NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createCharacterInstance);
 }
 
-static jlong NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createLineInstance);
 }
 
-static jlong NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createSentenceInstance);
 }
 
-static jlong NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createWordInstance);
 }
 
diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp
index 00ec9ae..4ce42ec 100644
--- a/luni/src/main/native/libcore_icu_NativeCollation.cpp
+++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp
@@ -180,11 +180,12 @@
     return result;
 }
 
-static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring localeName) {
-    ScopedUtfChars localeChars(env, localeName);
+static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring javaLocaleName) {
+    ScopedUtfChars localeChars(env, javaLocaleName);
     if (localeChars.c_str() == NULL) {
         return 0;
     }
+
     UErrorCode status = U_ZERO_ERROR;
     UCollator* c = ucol_open(localeChars.c_str(), &status);
     maybeThrowIcuException(env, "ucol_open", status);
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index ef1743e..faf87f1 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -20,6 +20,7 @@
 #include "JNIHelp.h"
 #include "JniConstants.h"
 #include "JniException.h"
+#include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
@@ -59,11 +60,14 @@
   return true;
 }
 
-static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring localeName, jobjectArray result) {
-  Locale locale = getLocale(env, localeName);
+static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring javaLocaleName, jobjectArray result) {
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return;
+  }
 
   UErrorCode status = U_ZERO_ERROR;
-  UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(locale, status));
+  UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
   if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
     return;
   }
@@ -118,11 +122,14 @@
   }
 }
 
-static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring javaLocale, jstring javaTz) {
-  Locale locale = getLocale(env, javaLocale);
+static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaTz) {
+  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  if (!icuLocale.valid()) {
+    return NULL;
+  }
 
   UErrorCode status = U_ZERO_ERROR;
-  UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(locale, status));
+  UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
   if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
     return NULL;
   }
diff --git a/luni/src/test/java/libcore/android/system/OsConstantsTest.java b/luni/src/test/java/libcore/android/system/OsConstantsTest.java
new file mode 100644
index 0000000..681d68c
--- /dev/null
+++ b/luni/src/test/java/libcore/android/system/OsConstantsTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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 android.system;
+
+import junit.framework.TestCase;
+
+public class OsConstantsTest extends TestCase {
+
+    // http://b/15602893
+    public void testBug15602893() {
+        assertTrue(OsConstants.RT_SCOPE_HOST > 0);
+        assertTrue(OsConstants.RT_SCOPE_LINK > 0);
+        assertTrue(OsConstants.RT_SCOPE_SITE > 0);
+
+        assertTrue(OsConstants.IFA_F_TENTATIVE > 0);
+    }
+}
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index 60ed0ca..be2da25 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -16,6 +16,8 @@
 
 package libcore.icu;
 
+import java.text.BreakIterator;
+import java.text.Collator;
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -42,12 +44,12 @@
   }
 
   public void test_getBestDateTimePattern() throws Exception {
-    assertEquals("d MMMM", ICU.getBestDateTimePattern("MMMMd", "ca_ES"));
-    assertEquals("d 'de' MMMM", ICU.getBestDateTimePattern("MMMMd", "es_ES"));
-    assertEquals("d. MMMM", ICU.getBestDateTimePattern("MMMMd", "de_CH"));
-    assertEquals("MMMM d", ICU.getBestDateTimePattern("MMMMd", "en_US"));
-    assertEquals("d LLLL", ICU.getBestDateTimePattern("MMMMd", "fa_IR"));
-    assertEquals("M月d日", ICU.getBestDateTimePattern("MMMMd", "ja_JP"));
+    assertEquals("d MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("ca", "ES")));
+    assertEquals("d 'de' MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("es", "ES")));
+    assertEquals("d. MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("de", "CH")));
+    assertEquals("MMMM d", ICU.getBestDateTimePattern("MMMMd", new Locale("en", "US")));
+    assertEquals("d LLLL", ICU.getBestDateTimePattern("MMMMd", new Locale("fa", "IR")));
+    assertEquals("M月d日", ICU.getBestDateTimePattern("MMMMd", new Locale("ja", "JP")));
   }
 
   public void test_localeFromString() throws Exception {
@@ -73,7 +75,7 @@
   }
 
   private String best(Locale l, String skeleton) {
-    return ICU.getBestDateTimePattern(skeleton, l.toString());
+    return ICU.getBestDateTimePattern(skeleton, l);
   }
 
   public void test_getDateFormatOrder() throws Exception {
@@ -123,4 +125,95 @@
     } catch (IllegalArgumentException expected) {
     }
   }
+
+  public void testScriptsPassedToIcu() throws Exception {
+    Locale sr_Cyrl_BA = Locale.forLanguageTag("sr-Cyrl-BA");
+    Locale sr_Cyrl_ME = Locale.forLanguageTag("sr-Cyrl-ME");
+    Locale sr_Latn_BA = Locale.forLanguageTag("sr-Latn-BA");
+    Locale sr_Latn_ME = Locale.forLanguageTag("sr-Latn-ME");
+
+    assertEquals("sr_BA_#Cyrl", sr_Cyrl_BA.toString());
+    assertEquals("Cyrl",        sr_Cyrl_BA.getScript());
+
+    assertEquals("sr_ME_#Cyrl", sr_Cyrl_ME.toString());
+    assertEquals("Cyrl",        sr_Cyrl_ME.getScript());
+
+    assertEquals("sr_BA_#Latn", sr_Latn_BA.toString());
+    assertEquals("Latn",        sr_Latn_BA.getScript());
+
+    assertEquals("sr_ME_#Latn", sr_Latn_ME.toString());
+    assertEquals("Latn",        sr_Latn_ME.getScript());
+
+    assertEquals("Српски",              sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
+    assertEquals("Босна и Херцеговина", sr_Cyrl_BA.getDisplayCountry(sr_Cyrl_BA));
+    assertEquals("Ћирилица",            sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
+    assertEquals("",                    sr_Cyrl_BA.getDisplayVariant(sr_Cyrl_BA));
+
+    assertEquals("Српски",    sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
+    assertEquals("Црна Гора", sr_Cyrl_ME.getDisplayCountry(sr_Cyrl_ME));
+    assertEquals("Ћирилица",  sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
+    assertEquals("",          sr_Cyrl_ME.getDisplayVariant(sr_Cyrl_ME));
+
+    assertEquals("Srpski",              sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
+    assertEquals("Bosna i Hercegovina", sr_Latn_BA.getDisplayCountry(sr_Latn_BA));
+    assertEquals("Latinica",            sr_Latn_BA.getDisplayScript(sr_Latn_BA));
+    assertEquals("",                    sr_Latn_BA.getDisplayVariant(sr_Latn_BA));
+
+    assertEquals("Srpski",    sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
+    assertEquals("Crna Gora", sr_Latn_ME.getDisplayCountry(sr_Latn_ME));
+    assertEquals("Latinica",  sr_Latn_ME.getDisplayScript(sr_Latn_ME));
+    assertEquals("",          sr_Latn_ME.getDisplayVariant(sr_Latn_ME));
+
+    assertEquals("BIH", sr_Cyrl_BA.getISO3Country());
+    assertEquals("srp", sr_Cyrl_BA.getISO3Language());
+    assertEquals("MNE", sr_Cyrl_ME.getISO3Country());
+    assertEquals("srp", sr_Cyrl_ME.getISO3Language());
+    assertEquals("BIH", sr_Latn_BA.getISO3Country());
+    assertEquals("srp", sr_Latn_BA.getISO3Language());
+    assertEquals("MNE", sr_Latn_ME.getISO3Country());
+    assertEquals("srp", sr_Latn_ME.getISO3Language());
+
+    BreakIterator.getCharacterInstance(sr_Cyrl_BA);
+    BreakIterator.getCharacterInstance(sr_Cyrl_ME);
+    BreakIterator.getCharacterInstance(sr_Latn_BA);
+    BreakIterator.getCharacterInstance(sr_Latn_ME);
+
+    BreakIterator.getLineInstance(sr_Cyrl_BA);
+    BreakIterator.getLineInstance(sr_Cyrl_ME);
+    BreakIterator.getLineInstance(sr_Latn_BA);
+    BreakIterator.getLineInstance(sr_Latn_ME);
+
+    BreakIterator.getSentenceInstance(sr_Cyrl_BA);
+    BreakIterator.getSentenceInstance(sr_Cyrl_ME);
+    BreakIterator.getSentenceInstance(sr_Latn_BA);
+    BreakIterator.getSentenceInstance(sr_Latn_ME);
+
+    BreakIterator.getWordInstance(sr_Cyrl_BA);
+    BreakIterator.getWordInstance(sr_Cyrl_ME);
+    BreakIterator.getWordInstance(sr_Latn_BA);
+    BreakIterator.getWordInstance(sr_Latn_ME);
+
+    Collator.getInstance(sr_Cyrl_BA);
+    Collator.getInstance(sr_Cyrl_ME);
+    Collator.getInstance(sr_Latn_BA);
+    Collator.getInstance(sr_Latn_ME);
+
+    // TODO: This needs to be fixed. We shouldn't output attribute key
+    // expansions in the language tag or the toString output. The tests
+    // will fail with something like:
+    //
+    // expected:<de-u-co[-phonebk-kf-upper-kn]> but was:
+    // <de-u-co[lcasefirst-upper-collation-phonebook-colnumeric-yes]>
+    Locale l = Locale.forLanguageTag("de-u-co-phonebk-kf-upper-kn");
+    assertEquals("de__#u-co-phonebk-kf-upper-kn", l.toString());
+    assertEquals("de-u-co-phonebk-kf-upper-kn", l.toLanguageTag());
+
+    Collator c = Collator.getInstance(l);
+    assertTrue(c.compare("2", "11") < 0);
+    assertTrue(c.compare("11", "ae") < 0);
+    assertTrue(c.compare("ae", "Ä") < 0);
+    assertTrue(c.compare("Ä", "ä") < 0);
+    assertTrue(c.compare("ä", "AF") < 0);
+    assertTrue(c.compare("AF", "af") < 0);
+  }
 }
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index b87dc97..0512b13 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -39,9 +39,22 @@
         // and variant, but a display name made up of the raw strings.
         // Newer releases return slightly different results, but no less unreasonable.
         assertEquals("aabbcc", invalid.getDisplayLanguage());
-        assertEquals("", invalid.getDisplayCountry());
-        assertEquals("DDEEFF_GGHHII", invalid.getDisplayVariant());
-        assertEquals("aabbcc (DDEEFF,DDEEFF_GGHHII)", invalid.getDisplayName());
+        assertEquals("DDEEFF", invalid.getDisplayCountry());
+        assertEquals("GGHHII", invalid.getDisplayVariant());
+        assertEquals("aabbcc (DDEEFF,GGHHII)", invalid.getDisplayName());
+    }
+
+    public void test_getDisplayName_emptyCodes() {
+        Locale emptyLanguage = new Locale("", "DdeEFf");
+        assertEquals("", emptyLanguage.getDisplayLanguage());
+
+        Locale emptyCountry = new Locale("AaBbCc", "");
+        assertEquals("", emptyCountry.getDisplayCountry());
+
+        Locale emptyCountryAndLanguage = new Locale("", "", "Farl");
+        assertEquals("", emptyCountryAndLanguage.getDisplayLanguage());
+        assertEquals("", emptyCountryAndLanguage.getDisplayCountry());
+        assertEquals("Farl", emptyCountryAndLanguage.getDisplayVariant());
     }
 
     // http://b/2611311; if there's no display language/country/variant, use the raw codes.
@@ -53,8 +66,8 @@
 
         assertEquals("xx", unknown.getDisplayLanguage());
         assertEquals("YY", unknown.getDisplayCountry());
-        assertEquals("TRADITIONAL", unknown.getDisplayVariant());
-        assertEquals("xx (YY,TRADITIONAL)", unknown.getDisplayName());
+        assertEquals("Traditional", unknown.getDisplayVariant());
+        assertEquals("xx (YY,Traditional)", unknown.getDisplayName());
     }
 
     public void test_getDisplayName_easy() throws Exception {