Merge "Remove Byte.toHexString() from core platform api"
am: ffb62b0923

Change-Id: I4881dc40d53243ea01e8177340e8569315c305cc
diff --git a/luni/src/main/java/libcore/util/TimeZoneFinder.java b/luni/src/main/java/libcore/util/TimeZoneFinder.java
new file mode 100644
index 0000000..c98decd
--- /dev/null
+++ b/luni/src/main/java/libcore/util/TimeZoneFinder.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+import android.icu.util.TimeZone;
+
+import java.util.List;
+
+// Used by com.google.android.setupwizard.hiddenapi.reflection.TimeZoneFinderReflection
+// Used by org.robolectric.shadows.ShadowTimeZoneFinder
+// Used by org.robolectric.shadows.ShadowTimeZoneFinderTest
+/**
+ * A shim class over {@link libcore.timezone.TimeZoneFinder} which used to be in
+ * {@code libcore.util}. This class provides just enough API to keep robolectric and SUW
+ * (setup wizard) working util those have been updated to use replacement public SDK APIs or adjust
+ * to the new package. See http://b/119921242 and http://b/116544863.
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+public final class TimeZoneFinder {
+
+    private static TimeZoneFinder instance;
+    private final libcore.timezone.TimeZoneFinder delegate;
+
+    private TimeZoneFinder(libcore.timezone.TimeZoneFinder delegate) {
+        this.delegate = delegate;
+    }
+
+    // Used by com.google.android.setupwizard.hiddenapi.reflection.TimeZoneFinderReflection
+    // Used by org.robolectric.shadows.ShadowTimeZoneFinderTest
+    /**
+     * Obtains an instance for use when resolving time zones. This method never returns
+     * {@code null}.
+     */
+    @libcore.api.CorePlatformApi
+    public static TimeZoneFinder getInstance() {
+        synchronized(TimeZoneFinder.class) {
+            if (instance == null) {
+                instance = new TimeZoneFinder(libcore.timezone.TimeZoneFinder.getInstance());
+            }
+        }
+        return instance;
+    }
+
+    // Used by org.robolectric.shadows.ShadowTimeZoneFinder
+    /** Used to create an instance using an in-memory XML String instead of a file. */
+    public static TimeZoneFinder createInstanceForTests(String xml) {
+        return new TimeZoneFinder(libcore.timezone.TimeZoneFinder.createInstanceForTests(xml));
+    }
+
+    // Used by com.google.android.setupwizard.hiddenapi.reflection.TimeZoneFinderReflection
+    // Used by org.robolectric.shadows.ShadowTimeZoneFinderTest
+    /**
+     * Returns an immutable list of frozen ICU time zones known to be used in the specified country.
+     * If the country code is not recognized or there is an error during lookup this can return
+     * null. The TimeZones returned will never contain {@link TimeZone#UNKNOWN_ZONE}. This method
+     * can return an empty list in a case when the underlying data files reference only unknown
+     * zone IDs.
+     */
+    @libcore.api.CorePlatformApi
+    public List<TimeZone> lookupTimeZonesByCountry(String countryIso) {
+        return delegate.lookupTimeZonesByCountry(countryIso);
+    }
+}
diff --git a/luni/src/test/java/libcore/libcore/util/TimeZoneFinderTest.java b/luni/src/test/java/libcore/libcore/util/TimeZoneFinderTest.java
new file mode 100644
index 0000000..aa1565b
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/util/TimeZoneFinderTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.libcore.util;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import android.icu.util.TimeZone;
+
+import java.util.List;
+import libcore.util.TimeZoneFinder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+public class TimeZoneFinderTest {
+
+    @Test
+    public void getInstance() throws Exception {
+        TimeZoneFinder finder1 = TimeZoneFinder.getInstance();
+        TimeZoneFinder finder2 = TimeZoneFinder.getInstance();
+        assertSame(finder1, finder2);
+    }
+
+    @Test
+    public void lookupTimeZonesByCountry() throws Exception {
+        TimeZoneFinder finder = TimeZoneFinder.createInstanceForTests(
+                "<timezones ianaversion=\"2017b\">\n"
+                + "  <countryzones>\n"
+                + "    <country code=\"gb\" default=\"Europe/London\" everutc=\"y\">\n"
+                + "      <id>Europe/London</id>\n"
+                + "    </country>\n"
+                + "  </countryzones>\n"
+                + "</timezones>\n");
+
+        List<TimeZone> gbList = finder.lookupTimeZonesByCountry("gb");
+        assertEquals(1, gbList.size());
+        assertImmutableList(gbList);
+        assertImmutableTimeZone(gbList.get(0));
+
+        // Check country code normalization works too.
+        assertEquals(1, finder.lookupTimeZonesByCountry("GB").size());
+
+        assertNull(finder.lookupTimeZonesByCountry("unknown"));
+    }
+
+    private static void assertImmutableTimeZone(TimeZone timeZone) {
+        try {
+            timeZone.setRawOffset(1000);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private static <X> void assertImmutableList(List<X> list) {
+        try {
+            list.add(null);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+}
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index da717bd..3686c20 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -1243,6 +1243,11 @@
     method public static void sneakyThrow(Throwable);
   }
 
+  public final class TimeZoneFinder {
+    method public static libcore.util.TimeZoneFinder getInstance();
+    method public java.util.List<android.icu.util.TimeZone> lookupTimeZonesByCountry(String);
+  }
+
   public class XmlObjectFactory {
     method public static org.xml.sax.XMLReader newXMLReader();
     method public static org.xmlpull.v1.XmlPullParser newXmlPullParser();
diff --git a/non_openjdk_java_files.bp b/non_openjdk_java_files.bp
index 3e4083f..9d65f04 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -196,6 +196,7 @@
         "luni/src/main/java/libcore/util/Nullable.java",
         "luni/src/main/java/libcore/util/SneakyThrow.java",
         "luni/src/main/java/libcore/util/XmlObjectFactory.java",
+        "luni/src/main/java/libcore/util/TimeZoneFinder.java",
         "luni/src/main/java/libcore/util/ZoneInfo.java",
         "dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java",
         "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java",