Merge "Return Olson ids from TimeZoneNames.forLocale in zone.tab order."
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index e71ec61..65ada89 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -16,12 +16,14 @@
package libcore.icu;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import libcore.util.BasicLruCache;
+import libcore.util.ZoneInfoDB;
/**
* Provides access to ICU's time zone name data.
@@ -140,12 +142,22 @@
/**
* Returns an array containing the time zone ids in use in the country corresponding to
* the given locale. This is not necessary for Java API, but is used by telephony as a
- * fallback.
+ * fallback. We retrieve these strings from zone.tab rather than icu4c because the latter
+ * supplies them in alphabetical order where zone.tab has them in a kind of "importance"
+ * order (as defined in the zone.tab header).
*/
public static String[] forLocale(Locale locale) {
- return forCountryCode(locale.getCountry());
+ String countryCode = locale.getCountry();
+ ArrayList<String> ids = new ArrayList<String>();
+ for (String line : ZoneInfoDB.getZoneTab().split("\n")) {
+ if (line.startsWith(countryCode)) {
+ int olsonIdStart = line.indexOf('\t', 4) + 1;
+ int olsonIdEnd = line.indexOf('\t', olsonIdStart);
+ ids.add(line.substring(olsonIdStart, olsonIdEnd));
+ }
+ }
+ return ids.toArray(new String[ids.size()]);
}
- private static native String[] forCountryCode(String countryCode);
private static native void fillZoneStrings(String locale, String[][] result);
}
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 2bf55ce..b211c93 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -55,6 +55,7 @@
private static final MemoryMappedFile TZDATA = mapData();
private static String version;
+ private static String zoneTab;
/**
* The 'ids' array contains time zone ids sorted alphabetically, for binary searching.
@@ -92,6 +93,7 @@
int zonetab_offset = it.readInt();
readIndex(it, index_offset, data_offset);
+ readZoneTab(it, zonetab_offset);
}
private static MemoryMappedFile mapData() {
@@ -113,6 +115,13 @@
}
}
+ private static void readZoneTab(BufferIterator it, int zoneTabOffset) {
+ byte[] bytes = new byte[(int) TZDATA.size() - zoneTabOffset];
+ it.seek(zoneTabOffset);
+ it.readByteArray(bytes, 0, bytes.length);
+ zoneTab = new String(bytes, 0, bytes.length, Charsets.US_ASCII);
+ }
+
private static void readIndex(BufferIterator it, int indexOffset, int dataOffset) {
it.seek(indexOffset);
@@ -211,4 +220,8 @@
public static String getVersion() {
return version;
}
+
+ public static String getZoneTab() {
+ return zoneTab;
+ }
}
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index 8e777f7..8c8682a 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -28,14 +28,6 @@
#include "unicode/timezone.h"
#include "unicode/tznames.h"
-static jobjectArray TimeZoneNames_forCountryCode(JNIEnv* env, jclass, jstring countryCode) {
- ScopedUtfChars countryChars(env, countryCode);
- if (countryChars.c_str() == NULL) {
- return NULL;
- }
- return fromStringEnumeration(env, TimeZone::createEnumeration(countryChars.c_str()));
-}
-
static bool isUtc(const UnicodeString& id) {
static const UnicodeString kEtcUct("Etc/UCT", 7, US_INV);
static const UnicodeString kEtcUtc("Etc/UTC", 7, US_INV);
@@ -119,7 +111,6 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(TimeZoneNames, forCountryCode, "(Ljava/lang/String;)[Ljava/lang/String;"),
NATIVE_METHOD(TimeZoneNames, fillZoneStrings, "(Ljava/lang/String;[[Ljava/lang/String;)V"),
};
void register_libcore_icu_TimeZoneNames(JNIEnv* env) {
diff --git a/luni/src/test/java/libcore/icu/TimeZoneNamesTest.java b/luni/src/test/java/libcore/icu/TimeZoneNamesTest.java
new file mode 100644
index 0000000..da8e035
--- /dev/null
+++ b/luni/src/test/java/libcore/icu/TimeZoneNamesTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 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.icu;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.HashSet;
+import java.util.TimeZone;
+
+public class TimeZoneNamesTest extends junit.framework.TestCase {
+ public void test_forLocale() throws Exception {
+ String[] ids = TimeZoneNames.forLocale(Locale.CANADA);
+ // Check that we got some ids.
+ assertTrue(ids.length > 0);
+ HashSet<String> allIds = new HashSet<String>(Arrays.asList(TimeZone.getAvailableIDs()));
+ // Check that they're all real.
+ for (String id : ids) {
+ assertTrue(allIds.contains(id));
+ }
+ // Check that Toronto comes before Atikokan. http://b/8391426.
+ int toronto = linearSearch(ids, "America/Toronto");
+ assertTrue(toronto >= 0);
+ int atikokan = linearSearch(ids, "America/Atikokan");
+ assertTrue(atikokan >= 0);
+ assertTrue(toronto < atikokan);
+ }
+
+ private int linearSearch(String[] xs, String x) {
+ for (int i = 0; i < xs.length; ++i) {
+ if (xs[i].equals(x)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}