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/JniConstants.h>
23#include <nativehelper/ScopedLocalRef.h>
24#include <nativehelper/ScopedUtfChars.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
34static 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
47static 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
100static JNINativeMethod gMethods[] = {
101  NATIVE_METHOD(TimeZoneNames, fillZoneStrings, "(Ljava/lang/String;[[Ljava/lang/String;)V"),
102};
103void register_libcore_icu_TimeZoneNames(JNIEnv* env) {
104  jniRegisterNativeMethods(env, "libcore/icu/TimeZoneNames", gMethods, NELEM(gMethods));
105}
106