1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "TimeZoneNames"
18 
19 #include <memory>
20 
21 #include <nativehelper/JNIHelp.h>
22 #include <nativehelper/ScopedLocalRef.h>
23 #include <nativehelper/ScopedUtfChars.h>
24 #include <nativehelper/jni_macros.h>
25 
26 #include "IcuUtilities.h"
27 #include "JniException.h"
28 #include "ScopedIcuLocale.h"
29 #include "ScopedJavaUnicodeString.h"
30 #include "unicode/calendar.h"
31 #include "unicode/timezone.h"
32 #include "unicode/tznames.h"
33 
setStringArrayElement(JNIEnv * env,jobjectArray array,int i,const icu::UnicodeString & s)34 static bool setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const icu::UnicodeString& s) {
35   // Don't use "GMT" string, for backwards compatibility.
36   static const icu::UnicodeString kGmt("GMT", 3, US_INV);
37   if (!s.isBogus() && !s.startsWith(kGmt)) {
38     ScopedLocalRef<jstring> javaString(env, jniCreateString(env, s.getBuffer(), s.length()));
39     if (javaString.get() == NULL) {
40       return false;
41     }
42     env->SetObjectArrayElement(array, i, javaString.get());
43   }
44   return true;
45 }
46 
TimeZoneNames_fillZoneStrings(JNIEnv * env,jclass,jstring javaLocaleName,jobjectArray result)47 static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring javaLocaleName, jobjectArray result) {
48   ScopedIcuLocale icuLocale(env, javaLocaleName);
49   if (!icuLocale.valid()) {
50     return;
51   }
52 
53   UErrorCode status = U_ZERO_ERROR;
54   std::unique_ptr<icu::TimeZoneNames> names(icu::TimeZoneNames::createInstance(icuLocale.locale(), status));
55   if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
56     return;
57   }
58 
59   const UDate now(icu::Calendar::getNow());
60 
61   size_t id_count = env->GetArrayLength(result);
62   for (size_t i = 0; i < id_count; ++i) {
63     ScopedLocalRef<jobjectArray> java_row(env,
64                                           reinterpret_cast<jobjectArray>(env->GetObjectArrayElement(result, i)));
65     ScopedLocalRef<jstring> java_zone_id(env,
66                                          reinterpret_cast<jstring>(env->GetObjectArrayElement(java_row.get(), 0)));
67     ScopedJavaUnicodeString zone_id(env, java_zone_id.get());
68     if (!zone_id.valid()) {
69       return;
70     }
71 
72     // Canonicalize the zone ID to the one known by ICU.
73     icu::UnicodeString lookup_id;
74     icu::TimeZone::getCanonicalID(zone_id.unicodeString(), lookup_id, status);
75     if (status != U_ZERO_ERROR) {
76       // Unknown ID - just use the zone ID we have.
77       lookup_id = zone_id.unicodeString();
78     }
79 
80     icu::UnicodeString long_std;
81     names->getDisplayName(lookup_id, UTZNM_LONG_STANDARD, now, long_std);
82     icu::UnicodeString short_std;
83     names->getDisplayName(lookup_id, UTZNM_SHORT_STANDARD, now, short_std);
84     icu::UnicodeString long_dst;
85     names->getDisplayName(lookup_id, UTZNM_LONG_DAYLIGHT, now, long_dst);
86     icu::UnicodeString short_dst;
87     names->getDisplayName(lookup_id, UTZNM_SHORT_DAYLIGHT, now, short_dst);
88 
89     bool okay =
90         setStringArrayElement(env, java_row.get(), 1, long_std) &&
91         setStringArrayElement(env, java_row.get(), 2, short_std) &&
92         setStringArrayElement(env, java_row.get(), 3, long_dst) &&
93         setStringArrayElement(env, java_row.get(), 4, short_dst);
94     if (!okay) {
95       return;
96     }
97   }
98 }
99 
100 static JNINativeMethod gMethods[] = {
101   NATIVE_METHOD(TimeZoneNames, fillZoneStrings, "(Ljava/lang/String;[[Ljava/lang/String;)V"),
102 };
register_libcore_icu_TimeZoneNames(JNIEnv * env)103 void register_libcore_icu_TimeZoneNames(JNIEnv* env) {
104   jniRegisterNativeMethods(env, "libcore/icu/TimeZoneNames", gMethods, NELEM(gMethods));
105 }
106