Merge commit '405aeb8a97eb0a5194c2803dde3968e10e1e509e' into HEAD
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
index 75a5218..e010116 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
@@ -22,6 +22,7 @@
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
+import java.util.concurrent.CountDownLatch;
 import libcore.java.lang.ref.FinalizationTester;
 
 public class ReferenceQueueTest extends junit.framework.TestCase {
@@ -198,27 +199,29 @@
         assertNull(rq.poll());
 
         class RemoveThread extends Thread {
+            public final CountDownLatch inBlock = new CountDownLatch(1);
+            public final CountDownLatch outOfBlock = new CountDownLatch(1);
             public void run() {
                 try {
+                    inBlock.countDown();
                     rq.remove(1000L);
                 } catch(InterruptedException ie) {
                     isThrown = true;
                 }
+                outOfBlock.countDown();
             }
         }
         RemoveThread rt = new RemoveThread();
         rt.start();
         try {
+            rt.inBlock.await();
+            // Try to be inside of rq.remove(1000L) if possible.
             Thread.sleep(10);
-        } catch(InterruptedException ie) {
-
-        }
+        } catch(InterruptedException ie) {}
         rt.interrupt();
         try {
-            Thread.sleep(10);
-        } catch(InterruptedException ie) {
-
-        }
+            rt.outOfBlock.await();
+        } catch(InterruptedException ie) {}
         assertTrue(isThrown);
         assertNull(rq.poll());
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index e4d6bd8..d52e586 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@
 import java.text.FieldPosition;
 import java.text.MessageFormat;
 import java.text.ParsePosition;
+import java.util.Locale;
 
 import junit.framework.TestCase;
 
@@ -466,4 +467,23 @@
 		assertEquals("GREATER_THAN_ONE", fmt.format(999999999D));
 		assertEquals("GREATER_THAN_ONE", fmt.format(Double.POSITIVE_INFINITY));
 	}
+
+    // http://b/19149384
+    public void testToPatternWithInfinities() {
+        final ChoiceFormat fmt = new ChoiceFormat(
+                "-\u221E<are negative|0<are fractions|1#is one|1.0<is 1+|\u221E<are many.");
+        assertEquals("-\u221E<are negative|0.0<are fractions|1.0#is one|1.0<is 1+|\u221E<are many.",
+                fmt.toPattern());
+    }
+
+    // http://b/19011159
+    public void testEscapedPatternWithConsecutiveQuotes() {
+        ChoiceFormat format = new ChoiceFormat("0#1'2''3'''4''''.");
+        String formatted = format.format(0);
+        assertEquals("12'3'4''.", formatted);
+
+        format = new ChoiceFormat("0#1'2''3'''''4''''.");
+        formatted = format.format(0);
+        assertEquals("12'3''4''.", formatted);
+    }
 }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
index 171f247..0920714 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
@@ -950,4 +950,12 @@
     String res = MessageFormat.format("bgcolor=\"{10}\"", messageArgs);
     assertEquals(res, "bgcolor=\"example10\"");
   }
+
+  // http://b/19011159
+  public void test19011159() {
+    final String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
+    final MessageFormat format = new MessageFormat(pattern, Locale.ENGLISH);
+    final Object[] zero0 = new Object[] { 0 };
+    assertEquals("ab12'3'4''.yz", format.format(zero0));
+  }
 }
diff --git a/luni/src/main/java/java/text/ChoiceFormat.java b/luni/src/main/java/java/text/ChoiceFormat.java
index 014b8c7..3d3cb3a 100644
--- a/luni/src/main/java/java/text/ChoiceFormat.java
+++ b/luni/src/main/java/java/text/ChoiceFormat.java
@@ -303,37 +303,16 @@
     }
 
     /**
-     * Returns the double value which is closest to the specified double but
-     * larger.
-     *
-     * @param value
-     *            a double value.
-     * @return the next larger double value.
+     * Equivalent to {@link Math#nextUp(double)}.
      */
     public static final double nextDouble(double value) {
-        if (value == Double.POSITIVE_INFINITY) {
-            return value;
-        }
-        long bits;
-        // Handle -0.0
-        if (value == 0) {
-            bits = 0;
-        } else {
-            bits = Double.doubleToLongBits(value);
-        }
-        return Double.longBitsToDouble(value < 0 ? bits - 1 : bits + 1);
+        return Math.nextUp(value);
     }
 
     /**
-     * Returns the double value which is closest to the specified double but
-     * either larger or smaller as specified.
-     *
-     * @param value
-     *            a double value.
-     * @param increment
-     *            {@code true} to get the next larger value, {@code false} to
-     *            get the previous smaller value.
-     * @return the next larger or smaller double value.
+     * Equivalent to {@link Math#nextUp(double)} if {@code increment == true}, and
+     * {@link Math#nextAfter(double, double)} with {@code direction == Double.NEGATIVE_INFINITY}
+     * otherwise.
      */
     public static double nextDouble(double value, boolean increment) {
         return increment ? nextDouble(value) : previousDouble(value);
@@ -385,25 +364,11 @@
     }
 
     /**
-     * Returns the double value which is closest to the specified double but
-     * smaller.
-     *
-     * @param value
-     *            a double value.
-     * @return the next smaller double value.
+     * Equivalent to {@link Math#nextAfter(double, double)} with
+     * {@code direction == Double.NEGATIVE_INFINITY}.
      */
     public static final double previousDouble(double value) {
-        if (value == Double.NEGATIVE_INFINITY) {
-            return value;
-        }
-        long bits;
-        // Handle 0.0
-        if (value == 0) {
-            bits = 0x8000000000000000L;
-        } else {
-            bits = Double.doubleToLongBits(value);
-        }
-        return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1);
+        return Math.nextAfter(value, Double.NEGATIVE_INFINITY);
     }
 
     /**
@@ -453,9 +418,30 @@
             if (i != 0) {
                 buffer.append('|');
             }
-            String previous = String.valueOf(previousDouble(choiceLimits[i]));
-            String limit = String.valueOf(choiceLimits[i]);
-            if (previous.length() < limit.length()) {
+
+            final String previous = String.valueOf(previousDouble(choiceLimits[i]));
+            final String limit = String.valueOf(choiceLimits[i]);
+
+            // Hack to make the output of toPattern parseable by another ChoiceFormat.
+            // String.valueOf() will emit "Infinity", which isn't parseable by our NumberFormat
+            // instances.
+            //
+            // Ideally, we'd just use NumberFormat.format() to emit output (to be symmetric with
+            // our usage of NumberFormat.parse()) but it's hard set the right number of significant
+            // digits in order to output a format string that's equivalent to the original input.
+            if (Double.isInfinite(choiceLimits[i]) ||
+                    Double.isInfinite(previousDouble(choiceLimits[i]))) {
+                if (choiceLimits[i] < 0) {
+                    buffer.append("-\u221E");
+                    buffer.append('<');
+                } else {
+                    buffer.append('\u221E');
+                    buffer.append('<');
+                }
+            } else if (previous.length() < limit.length()) {
+                // What the... i don't even.... sigh. This is trying to figure out whether the
+                // element was a "<" or a "#". The idea being that users will specify "reasonable"
+                // quantities and calling nextDouble will result in a "longer" number in most cases.
                 buffer.append(previous);
                 buffer.append('<');
             } else {
diff --git a/luni/src/main/java/java/text/Format.java b/luni/src/main/java/java/text/Format.java
index 58671fa..c4dc5f0 100644
--- a/luni/src/main/java/java/text/Format.java
+++ b/luni/src/main/java/java/text/Format.java
@@ -177,23 +177,26 @@
     static boolean upTo(String string, ParsePosition position,
             StringBuffer buffer, char stop) {
         int index = position.getIndex(), length = string.length();
-        boolean lastQuote = false, quote = false;
+
+        int numConsecutiveQuotes = 0;
+        boolean quote = false;
         while (index < length) {
             char ch = string.charAt(index++);
             if (ch == '\'') {
-                if (lastQuote) {
+                ++numConsecutiveQuotes;
+                if (numConsecutiveQuotes != 0 && numConsecutiveQuotes % 2 == 0) {
                     buffer.append('\'');
                 }
                 quote = !quote;
-                lastQuote = true;
             } else if (ch == stop && !quote) {
                 position.setIndex(index);
                 return true;
             } else {
-                lastQuote = false;
+                numConsecutiveQuotes = 0;
                 buffer.append(ch);
             }
         }
+
         position.setIndex(index);
         return false;
     }
diff --git a/luni/src/main/java/java/text/MessageFormat.java b/luni/src/main/java/java/text/MessageFormat.java
index cf306a7..f48cebd 100644
--- a/luni/src/main/java/java/text/MessageFormat.java
+++ b/luni/src/main/java/java/text/MessageFormat.java
@@ -580,6 +580,12 @@
             }
             if (format instanceof ChoiceFormat) {
                 String result = format.format(arg);
+                // Escape quotes in the result because the ChoiceFormat would've already
+                // dealt with them for us. In other words, any quotes that are present in the
+                // result are due to escaped quotes in the original input. We should preserve
+                // them in the output instead of having them processed again with the message
+                // format we're creating below.
+                result = result.replace("'", "''");
                 MessageFormat mf = new MessageFormat(result);
                 mf.setLocale(locale);
                 mf.format(objects, buffer, passedField);