xref: /aosp_15_r20/external/libtextclassifier/native/utils/calendar/calendar-javaicu.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker #include "utils/calendar/calendar-javaicu.h"
18*993b0882SAndroid Build Coastguard Worker 
19*993b0882SAndroid Build Coastguard Worker #include "annotator/types.h"
20*993b0882SAndroid Build Coastguard Worker #include "utils/base/statusor.h"
21*993b0882SAndroid Build Coastguard Worker #include "utils/java/jni-base.h"
22*993b0882SAndroid Build Coastguard Worker #include "utils/java/jni-helper.h"
23*993b0882SAndroid Build Coastguard Worker 
24*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
25*993b0882SAndroid Build Coastguard Worker namespace {
26*993b0882SAndroid Build Coastguard Worker 
27*993b0882SAndroid Build Coastguard Worker // Generic version of icu::Calendar::add with error checking.
CalendarAdd(JniCache * jni_cache,JNIEnv * jenv,jobject calendar,jint field,jint value)28*993b0882SAndroid Build Coastguard Worker bool CalendarAdd(JniCache* jni_cache, JNIEnv* jenv, jobject calendar,
29*993b0882SAndroid Build Coastguard Worker                  jint field, jint value) {
30*993b0882SAndroid Build Coastguard Worker   return JniHelper::CallVoidMethod(jenv, calendar, jni_cache->calendar_add,
31*993b0882SAndroid Build Coastguard Worker                                    field, value)
32*993b0882SAndroid Build Coastguard Worker       .ok();
33*993b0882SAndroid Build Coastguard Worker }
34*993b0882SAndroid Build Coastguard Worker 
35*993b0882SAndroid Build Coastguard Worker // Generic version of icu::Calendar::get with error checking.
CalendarGet(JniCache * jni_cache,JNIEnv * jenv,jobject calendar,jint field,jint * value)36*993b0882SAndroid Build Coastguard Worker bool CalendarGet(JniCache* jni_cache, JNIEnv* jenv, jobject calendar,
37*993b0882SAndroid Build Coastguard Worker                  jint field, jint* value) {
38*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(
39*993b0882SAndroid Build Coastguard Worker       *value,
40*993b0882SAndroid Build Coastguard Worker       JniHelper::CallIntMethod(jenv, calendar, jni_cache->calendar_get, field));
41*993b0882SAndroid Build Coastguard Worker   return true;
42*993b0882SAndroid Build Coastguard Worker }
43*993b0882SAndroid Build Coastguard Worker 
44*993b0882SAndroid Build Coastguard Worker // Generic version of icu::Calendar::set with error checking.
CalendarSet(JniCache * jni_cache,JNIEnv * jenv,jobject calendar,jint field,jint value)45*993b0882SAndroid Build Coastguard Worker bool CalendarSet(JniCache* jni_cache, JNIEnv* jenv, jobject calendar,
46*993b0882SAndroid Build Coastguard Worker                  jint field, jint value) {
47*993b0882SAndroid Build Coastguard Worker   return JniHelper::CallVoidMethod(jenv, calendar, jni_cache->calendar_set,
48*993b0882SAndroid Build Coastguard Worker                                    field, value)
49*993b0882SAndroid Build Coastguard Worker       .ok();
50*993b0882SAndroid Build Coastguard Worker }
51*993b0882SAndroid Build Coastguard Worker 
52*993b0882SAndroid Build Coastguard Worker // Extracts the first tag from a BCP47 tag (e.g. "en" for "en-US").
GetFirstBcp47Tag(const std::string & tag)53*993b0882SAndroid Build Coastguard Worker std::string GetFirstBcp47Tag(const std::string& tag) {
54*993b0882SAndroid Build Coastguard Worker   for (size_t i = 0; i < tag.size(); ++i) {
55*993b0882SAndroid Build Coastguard Worker     if (tag[i] == '_' || tag[i] == '-') {
56*993b0882SAndroid Build Coastguard Worker       return std::string(tag, 0, i);
57*993b0882SAndroid Build Coastguard Worker     }
58*993b0882SAndroid Build Coastguard Worker   }
59*993b0882SAndroid Build Coastguard Worker   return tag;
60*993b0882SAndroid Build Coastguard Worker }
61*993b0882SAndroid Build Coastguard Worker 
62*993b0882SAndroid Build Coastguard Worker }  // anonymous namespace
63*993b0882SAndroid Build Coastguard Worker 
Calendar(JniCache * jni_cache)64*993b0882SAndroid Build Coastguard Worker Calendar::Calendar(JniCache* jni_cache)
65*993b0882SAndroid Build Coastguard Worker     : jni_cache_(jni_cache),
66*993b0882SAndroid Build Coastguard Worker       jenv_(jni_cache_ ? jni_cache->GetEnv() : nullptr),
67*993b0882SAndroid Build Coastguard Worker       calendar_(nullptr, jenv_) {}
68*993b0882SAndroid Build Coastguard Worker 
Initialize(const std::string & time_zone,const std::string & locale,int64 time_ms_utc)69*993b0882SAndroid Build Coastguard Worker bool Calendar::Initialize(const std::string& time_zone,
70*993b0882SAndroid Build Coastguard Worker                           const std::string& locale, int64 time_ms_utc) {
71*993b0882SAndroid Build Coastguard Worker   if (!jni_cache_ || !jenv_) {
72*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Initialize without env";
73*993b0882SAndroid Build Coastguard Worker     return false;
74*993b0882SAndroid Build Coastguard Worker   }
75*993b0882SAndroid Build Coastguard Worker 
76*993b0882SAndroid Build Coastguard Worker   // We'll assume the day indices match later on, so verify it here.
77*993b0882SAndroid Build Coastguard Worker   if (jni_cache_->calendar_sunday != kSunday ||
78*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_monday != kMonday ||
79*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_tuesday != kTuesday ||
80*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_wednesday != kWednesday ||
81*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_thursday != kThursday ||
82*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_friday != kFriday ||
83*993b0882SAndroid Build Coastguard Worker       jni_cache_->calendar_saturday != kSaturday) {
84*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "day of the week indices mismatch";
85*993b0882SAndroid Build Coastguard Worker     return false;
86*993b0882SAndroid Build Coastguard Worker   }
87*993b0882SAndroid Build Coastguard Worker 
88*993b0882SAndroid Build Coastguard Worker   // Get the time zone.
89*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(ScopedLocalRef<jstring> java_time_zone_str,
90*993b0882SAndroid Build Coastguard Worker                              JniHelper::NewStringUTF(jenv_, time_zone.c_str()));
91*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(
92*993b0882SAndroid Build Coastguard Worker       ScopedLocalRef<jobject> java_time_zone,
93*993b0882SAndroid Build Coastguard Worker       JniHelper::CallStaticObjectMethod(jenv_, jni_cache_->timezone_class.get(),
94*993b0882SAndroid Build Coastguard Worker                                         jni_cache_->timezone_get_timezone,
95*993b0882SAndroid Build Coastguard Worker                                         java_time_zone_str.get()));
96*993b0882SAndroid Build Coastguard Worker   if (java_time_zone == nullptr) {
97*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "failed to get timezone";
98*993b0882SAndroid Build Coastguard Worker     return false;
99*993b0882SAndroid Build Coastguard Worker   }
100*993b0882SAndroid Build Coastguard Worker 
101*993b0882SAndroid Build Coastguard Worker   // Get the locale.
102*993b0882SAndroid Build Coastguard Worker   ScopedLocalRef<jobject> java_locale(nullptr, jenv_);
103*993b0882SAndroid Build Coastguard Worker   if (jni_cache_->locale_for_language_tag) {
104*993b0882SAndroid Build Coastguard Worker     // API level 21+, we can actually parse language tags.
105*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN_FALSE(ScopedLocalRef<jstring> java_locale_str,
106*993b0882SAndroid Build Coastguard Worker                                JniHelper::NewStringUTF(jenv_, locale.c_str()));
107*993b0882SAndroid Build Coastguard Worker 
108*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN_FALSE(
109*993b0882SAndroid Build Coastguard Worker         java_locale,
110*993b0882SAndroid Build Coastguard Worker         JniHelper::CallStaticObjectMethod(jenv_, jni_cache_->locale_class.get(),
111*993b0882SAndroid Build Coastguard Worker                                           jni_cache_->locale_for_language_tag,
112*993b0882SAndroid Build Coastguard Worker                                           java_locale_str.get()));
113*993b0882SAndroid Build Coastguard Worker   } else {
114*993b0882SAndroid Build Coastguard Worker     // API level <21. We can't parse tags, so we just use the language.
115*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN_FALSE(
116*993b0882SAndroid Build Coastguard Worker         ScopedLocalRef<jstring> java_language_str,
117*993b0882SAndroid Build Coastguard Worker         JniHelper::NewStringUTF(jenv_, GetFirstBcp47Tag(locale).c_str()));
118*993b0882SAndroid Build Coastguard Worker 
119*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN_FALSE(
120*993b0882SAndroid Build Coastguard Worker         java_locale, JniHelper::NewObject(jenv_, jni_cache_->locale_class.get(),
121*993b0882SAndroid Build Coastguard Worker                                           jni_cache_->locale_init_string,
122*993b0882SAndroid Build Coastguard Worker                                           java_language_str.get()));
123*993b0882SAndroid Build Coastguard Worker   }
124*993b0882SAndroid Build Coastguard Worker   if (java_locale == nullptr) {
125*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "failed to get locale";
126*993b0882SAndroid Build Coastguard Worker     return false;
127*993b0882SAndroid Build Coastguard Worker   }
128*993b0882SAndroid Build Coastguard Worker 
129*993b0882SAndroid Build Coastguard Worker   // Get the calendar.
130*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(
131*993b0882SAndroid Build Coastguard Worker       calendar_, JniHelper::CallStaticObjectMethod(
132*993b0882SAndroid Build Coastguard Worker                      jenv_, jni_cache_->calendar_class.get(),
133*993b0882SAndroid Build Coastguard Worker                      jni_cache_->calendar_get_instance, java_time_zone.get(),
134*993b0882SAndroid Build Coastguard Worker                      java_locale.get()));
135*993b0882SAndroid Build Coastguard Worker   if (calendar_ == nullptr) {
136*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "failed to get calendar";
137*993b0882SAndroid Build Coastguard Worker     return false;
138*993b0882SAndroid Build Coastguard Worker   }
139*993b0882SAndroid Build Coastguard Worker 
140*993b0882SAndroid Build Coastguard Worker   // Set the time.
141*993b0882SAndroid Build Coastguard Worker   if (!JniHelper::CallVoidMethod(jenv_, calendar_.get(),
142*993b0882SAndroid Build Coastguard Worker                                  jni_cache_->calendar_set_time_in_millis,
143*993b0882SAndroid Build Coastguard Worker                                  time_ms_utc)
144*993b0882SAndroid Build Coastguard Worker            .ok()) {
145*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "failed to set time";
146*993b0882SAndroid Build Coastguard Worker     return false;
147*993b0882SAndroid Build Coastguard Worker   }
148*993b0882SAndroid Build Coastguard Worker   return true;
149*993b0882SAndroid Build Coastguard Worker }
150*993b0882SAndroid Build Coastguard Worker 
GetFirstDayOfWeek(int * value) const151*993b0882SAndroid Build Coastguard Worker bool Calendar::GetFirstDayOfWeek(int* value) const {
152*993b0882SAndroid Build Coastguard Worker   if (!jni_cache_ || !jenv_ || !calendar_) return false;
153*993b0882SAndroid Build Coastguard Worker 
154*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(
155*993b0882SAndroid Build Coastguard Worker       *value,
156*993b0882SAndroid Build Coastguard Worker       JniHelper::CallIntMethod(jenv_, calendar_.get(),
157*993b0882SAndroid Build Coastguard Worker                                jni_cache_->calendar_get_first_day_of_week));
158*993b0882SAndroid Build Coastguard Worker   return true;
159*993b0882SAndroid Build Coastguard Worker }
160*993b0882SAndroid Build Coastguard Worker 
GetTimeInMillis(int64 * value) const161*993b0882SAndroid Build Coastguard Worker bool Calendar::GetTimeInMillis(int64* value) const {
162*993b0882SAndroid Build Coastguard Worker   if (!jni_cache_ || !jenv_ || !calendar_) return false;
163*993b0882SAndroid Build Coastguard Worker 
164*993b0882SAndroid Build Coastguard Worker   TC3_ASSIGN_OR_RETURN_FALSE(
165*993b0882SAndroid Build Coastguard Worker       *value,
166*993b0882SAndroid Build Coastguard Worker       JniHelper::CallLongMethod(jenv_, calendar_.get(),
167*993b0882SAndroid Build Coastguard Worker                                 jni_cache_->calendar_get_time_in_millis));
168*993b0882SAndroid Build Coastguard Worker 
169*993b0882SAndroid Build Coastguard Worker   return true;
170*993b0882SAndroid Build Coastguard Worker }
171*993b0882SAndroid Build Coastguard Worker 
CalendarLib()172*993b0882SAndroid Build Coastguard Worker CalendarLib::CalendarLib() {
173*993b0882SAndroid Build Coastguard Worker   TC3_LOG(FATAL) << "Java ICU CalendarLib must be initialized with a JniCache.";
174*993b0882SAndroid Build Coastguard Worker }
175*993b0882SAndroid Build Coastguard Worker 
CalendarLib(const std::shared_ptr<JniCache> & jni_cache)176*993b0882SAndroid Build Coastguard Worker CalendarLib::CalendarLib(const std::shared_ptr<JniCache>& jni_cache)
177*993b0882SAndroid Build Coastguard Worker     : jni_cache_(jni_cache) {}
178*993b0882SAndroid Build Coastguard Worker 
179*993b0882SAndroid Build Coastguard Worker // Below is the boilerplate code for implementing the specialisations of
180*993b0882SAndroid Build Coastguard Worker // get/set/add for the various field types.
181*993b0882SAndroid Build Coastguard Worker #define TC3_DEFINE_FIELD_ACCESSOR(NAME, FIELD, KIND, TYPE)      \
182*993b0882SAndroid Build Coastguard Worker   bool Calendar::KIND##NAME(TYPE value) const {                 \
183*993b0882SAndroid Build Coastguard Worker     if (!jni_cache_ || !jenv_ || !calendar_) return false;      \
184*993b0882SAndroid Build Coastguard Worker     return Calendar##KIND(jni_cache_, jenv_, calendar_.get(),   \
185*993b0882SAndroid Build Coastguard Worker                           jni_cache_->calendar_##FIELD, value); \
186*993b0882SAndroid Build Coastguard Worker   }
187*993b0882SAndroid Build Coastguard Worker #define TC3_DEFINE_ADD(NAME, CONST) \
188*993b0882SAndroid Build Coastguard Worker   TC3_DEFINE_FIELD_ACCESSOR(NAME, CONST, Add, int)
189*993b0882SAndroid Build Coastguard Worker #define TC3_DEFINE_SET(NAME, CONST) \
190*993b0882SAndroid Build Coastguard Worker   TC3_DEFINE_FIELD_ACCESSOR(NAME, CONST, Set, int)
191*993b0882SAndroid Build Coastguard Worker #define TC3_DEFINE_GET(NAME, CONST) \
192*993b0882SAndroid Build Coastguard Worker   TC3_DEFINE_FIELD_ACCESSOR(NAME, CONST, Get, int*)
193*993b0882SAndroid Build Coastguard Worker 
194*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(Second, second)
195*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(Minute, minute)
196*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(HourOfDay, hour_of_day)
197*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(DayOfMonth, day_of_month)
198*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(Year, year)
199*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_ADD(Month, month)
200*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_GET(DayOfWeek, day_of_week)
201*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(ZoneOffset, zone_offset)
202*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(DstOffset, dst_offset)
203*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(Year, year)
204*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(Month, month)
205*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(DayOfYear, day_of_year)
206*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(DayOfMonth, day_of_month)
207*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(DayOfWeek, day_of_week)
208*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(HourOfDay, hour_of_day)
209*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(Minute, minute)
210*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(Second, second)
211*993b0882SAndroid Build Coastguard Worker TC3_DEFINE_SET(Millisecond, millisecond)
212*993b0882SAndroid Build Coastguard Worker 
213*993b0882SAndroid Build Coastguard Worker #undef TC3_DEFINE_FIELD_ACCESSOR
214*993b0882SAndroid Build Coastguard Worker #undef TC3_DEFINE_ADD
215*993b0882SAndroid Build Coastguard Worker #undef TC3_DEFINE_SET
216*993b0882SAndroid Build Coastguard Worker #undef TC3_DEFINE_GET
217*993b0882SAndroid Build Coastguard Worker 
218*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
219