| /* |
| ** Copyright 2006, 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. |
| */ |
| |
| #define LOG_TAG "Log_println" |
| |
| #include <utils/Log.h> |
| #include <utils/String8.h> |
| #include <assert.h> |
| |
| #include "jni.h" |
| #include "utils/misc.h" |
| #include "android_runtime/AndroidRuntime.h" |
| #include "TimeUtils.h" |
| #include <nativehelper/JNIHelp.h> |
| #include <cutils/tztime.h> |
| |
| namespace android { |
| |
| static jfieldID g_allDayField = 0; |
| static jfieldID g_secField = 0; |
| static jfieldID g_minField = 0; |
| static jfieldID g_hourField = 0; |
| static jfieldID g_mdayField = 0; |
| static jfieldID g_monField = 0; |
| static jfieldID g_yearField = 0; |
| static jfieldID g_wdayField = 0; |
| static jfieldID g_ydayField = 0; |
| static jfieldID g_isdstField = 0; |
| static jfieldID g_gmtoffField = 0; |
| static jfieldID g_timezoneField = 0; |
| |
| static jfieldID g_shortMonthsField = 0; |
| static jfieldID g_longMonthsField = 0; |
| static jfieldID g_longStandaloneMonthsField = 0; |
| static jfieldID g_shortWeekdaysField = 0; |
| static jfieldID g_longWeekdaysField = 0; |
| static jfieldID g_timeOnlyFormatField = 0; |
| static jfieldID g_dateOnlyFormatField = 0; |
| static jfieldID g_dateTimeFormatField = 0; |
| static jfieldID g_amField = 0; |
| static jfieldID g_pmField = 0; |
| static jfieldID g_dateCommandField = 0; |
| static jfieldID g_localeField = 0; |
| |
| static jclass g_timeClass = NULL; |
| |
| static inline bool java2time(JNIEnv* env, Time* t, jobject o) |
| { |
| t->t.tm_sec = env->GetIntField(o, g_secField); |
| t->t.tm_min = env->GetIntField(o, g_minField); |
| t->t.tm_hour = env->GetIntField(o, g_hourField); |
| t->t.tm_mday = env->GetIntField(o, g_mdayField); |
| t->t.tm_mon = env->GetIntField(o, g_monField); |
| t->t.tm_year = (env->GetIntField(o, g_yearField))-1900; |
| t->t.tm_wday = env->GetIntField(o, g_wdayField); |
| t->t.tm_yday = env->GetIntField(o, g_ydayField); |
| t->t.tm_isdst = env->GetIntField(o, g_isdstField); |
| t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField); |
| bool allDay = env->GetIntField(o, g_allDayField); |
| if (allDay && |
| ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) { |
| char msg[100]; |
| sprintf(msg, "allDay is true but sec, min, hour are not 0."); |
| jniThrowException(env, "java/lang/IllegalArgumentException", msg); |
| return false; |
| } |
| return true; |
| } |
| |
| static inline void time2java(JNIEnv* env, jobject o, const Time &t) |
| { |
| env->SetIntField(o, g_secField, t.t.tm_sec); |
| env->SetIntField(o, g_minField, t.t.tm_min); |
| env->SetIntField(o, g_hourField, t.t.tm_hour); |
| env->SetIntField(o, g_mdayField, t.t.tm_mday); |
| env->SetIntField(o, g_monField, t.t.tm_mon); |
| env->SetIntField(o, g_yearField, t.t.tm_year+1900); |
| env->SetIntField(o, g_wdayField, t.t.tm_wday); |
| env->SetIntField(o, g_ydayField, t.t.tm_yday); |
| env->SetIntField(o, g_isdstField, t.t.tm_isdst); |
| env->SetLongField(o, g_gmtoffField, t.t.tm_gmtoff); |
| } |
| |
| #define ACQUIRE_TIMEZONE(This, t) \ |
| jstring timezoneString_##This \ |
| = (jstring) env->GetObjectField(This, g_timezoneField); \ |
| t.timezone = env->GetStringUTFChars(timezoneString_##This, NULL); |
| |
| #define RELEASE_TIMEZONE(This, t) \ |
| env->ReleaseStringUTFChars(timezoneString_##This, t.timezone); |
| |
| |
| // ============================================================================ |
| |
| static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This, |
| jboolean ignoreDst) |
| { |
| Time t; |
| if (!java2time(env, &t, This)) return 0L; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| int64_t result = t.toMillis(ignoreDst != 0); |
| |
| time2java(env, This, t); |
| RELEASE_TIMEZONE(This, t) |
| |
| return result; |
| } |
| |
| static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This, |
| jstring timezoneObject) |
| { |
| Time t; |
| if (!java2time(env, &t, This)) return; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| const char* timezone = env->GetStringUTFChars(timezoneObject, NULL); |
| |
| t.switchTimezone(timezone); |
| |
| time2java(env, This, t); |
| env->ReleaseStringUTFChars(timezoneObject, timezone); |
| RELEASE_TIMEZONE(This, t) |
| |
| // we do this here because there's no point in reallocating the string |
| env->SetObjectField(This, g_timezoneField, timezoneObject); |
| } |
| |
| static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz, |
| jobject aObject, jobject bObject) |
| { |
| Time a, b; |
| |
| if (!java2time(env, &a, aObject)) return 0; |
| ACQUIRE_TIMEZONE(aObject, a) |
| |
| if (!java2time(env, &b, bObject)) return 0; |
| ACQUIRE_TIMEZONE(bObject, b) |
| |
| int result = Time::compare(a, b); |
| |
| RELEASE_TIMEZONE(aObject, a) |
| RELEASE_TIMEZONE(bObject, b) |
| |
| return result; |
| } |
| |
| static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This) |
| { |
| Time t; |
| if (!java2time(env, &t, This)) return env->NewStringUTF(""); |
| bool allDay = env->GetIntField(This, g_allDayField); |
| |
| if (!allDay) { |
| ACQUIRE_TIMEZONE(This, t) |
| bool inUtc = strcmp("UTC", t.timezone) == 0; |
| short buf[16]; |
| t.format2445(buf, true); |
| RELEASE_TIMEZONE(This, t) |
| if (inUtc) { |
| // The letter 'Z' is appended to the end so allow for one |
| // more character in the buffer. |
| return env->NewString((jchar*)buf, 16); |
| } else { |
| return env->NewString((jchar*)buf, 15); |
| } |
| } else { |
| short buf[8]; |
| t.format2445(buf, false); |
| return env->NewString((jchar*)buf, 8); |
| } |
| } |
| |
| static jstring android_text_format_Time_format(JNIEnv* env, jobject This, |
| jstring formatObject) |
| { |
| // We only teardown and setup our 'locale' struct and other state |
| // when the Java-side locale changed. This is safe to do here |
| // without locking because we're always called from Java code |
| // synchronized on the class instance. |
| static jobject js_locale_previous = NULL; |
| static struct strftime_locale locale; |
| static jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7]; |
| static jstring js_standalone_month[12]; |
| static jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt; |
| |
| Time t; |
| if (!java2time(env, &t, This)) return env->NewStringUTF(""); |
| |
| jclass timeClass = g_timeClass; |
| jobject js_locale = (jobject) env->GetStaticObjectField(timeClass, g_localeField); |
| if (js_locale_previous != js_locale) { |
| if (js_locale_previous != NULL) { |
| // Free the old one. |
| for (int i = 0; i < 12; i++) { |
| env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]); |
| env->ReleaseStringUTFChars(js_month[i], locale.month[i]); |
| env->ReleaseStringUTFChars(js_standalone_month[i], locale.standalone_month[i]); |
| env->DeleteGlobalRef(js_mon[i]); |
| env->DeleteGlobalRef(js_month[i]); |
| env->DeleteGlobalRef(js_standalone_month[i]); |
| } |
| |
| for (int i = 0; i < 7; i++) { |
| env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]); |
| env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]); |
| env->DeleteGlobalRef(js_wday[i]); |
| env->DeleteGlobalRef(js_weekday[i]); |
| } |
| |
| env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt); |
| env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt); |
| env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt); |
| env->ReleaseStringUTFChars(js_am, locale.am); |
| env->ReleaseStringUTFChars(js_pm, locale.pm); |
| env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt); |
| env->DeleteGlobalRef(js_X_fmt); |
| env->DeleteGlobalRef(js_x_fmt); |
| env->DeleteGlobalRef(js_c_fmt); |
| env->DeleteGlobalRef(js_am); |
| env->DeleteGlobalRef(js_pm); |
| env->DeleteGlobalRef(js_date_fmt); |
| } |
| js_locale_previous = js_locale; |
| |
| jobjectArray ja; |
| ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField); |
| for (int i = 0; i < 12; i++) { |
| js_mon[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i)); |
| locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL); |
| } |
| |
| ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField); |
| for (int i = 0; i < 12; i++) { |
| js_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i)); |
| locale.month[i] = env->GetStringUTFChars(js_month[i], NULL); |
| } |
| |
| ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longStandaloneMonthsField); |
| for (int i = 0; i < 12; i++) { |
| js_standalone_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i)); |
| locale.standalone_month[i] = env->GetStringUTFChars(js_standalone_month[i], NULL); |
| } |
| |
| ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField); |
| for (int i = 0; i < 7; i++) { |
| js_wday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i)); |
| locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL); |
| } |
| |
| ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField); |
| for (int i = 0; i < 7; i++) { |
| js_weekday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i)); |
| locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL); |
| } |
| |
| js_X_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_timeOnlyFormatField)); |
| locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL); |
| |
| js_x_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_dateOnlyFormatField)); |
| locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL); |
| |
| js_c_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_dateTimeFormatField)); |
| locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL); |
| |
| js_am = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_amField)); |
| locale.am = env->GetStringUTFChars(js_am, NULL); |
| |
| js_pm = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_pmField)); |
| locale.pm = env->GetStringUTFChars(js_pm, NULL); |
| |
| js_date_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField( |
| timeClass, g_dateCommandField)); |
| locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL); |
| } |
| |
| ACQUIRE_TIMEZONE(This, t) |
| |
| const char* format = env->GetStringUTFChars(formatObject, NULL); |
| |
| String8 r = t.format(format, &locale); |
| |
| env->ReleaseStringUTFChars(formatObject, format); |
| RELEASE_TIMEZONE(This, t) |
| |
| return env->NewStringUTF(r.string()); |
| } |
| |
| |
| static jstring android_text_format_Time_toString(JNIEnv* env, jobject This) |
| { |
| Time t; |
| if (!java2time(env, &t, This)) return env->NewStringUTF("");; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| String8 r = t.toString(); |
| |
| RELEASE_TIMEZONE(This, t) |
| |
| return env->NewStringUTF(r.string()); |
| } |
| |
| static void android_text_format_Time_setToNow(JNIEnv* env, jobject This) |
| { |
| env->SetBooleanField(This, g_allDayField, JNI_FALSE); |
| Time t; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| t.setToNow(); |
| |
| time2java(env, This, t); |
| RELEASE_TIMEZONE(This, t) |
| } |
| |
| static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This, |
| jboolean ignoreDst) |
| { |
| Time t; |
| if (!java2time(env, &t, This)) return 0L; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| int64_t result = t.toMillis(ignoreDst != 0); |
| |
| RELEASE_TIMEZONE(This, t) |
| |
| return result; |
| } |
| |
| static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis) |
| { |
| env->SetBooleanField(This, g_allDayField, JNI_FALSE); |
| Time t; |
| ACQUIRE_TIMEZONE(This, t) |
| |
| t.set(millis); |
| |
| time2java(env, This, t); |
| RELEASE_TIMEZONE(This, t) |
| } |
| |
| |
| // ============================================================================ |
| // Just do this here because it's not worth recreating the strings |
| |
| static int get_char(JNIEnv* env, const jchar *s, int spos, int mul, |
| bool *thrown) |
| { |
| jchar c = s[spos]; |
| if (c >= '0' && c <= '9') { |
| return (c - '0') * mul; |
| } else { |
| if (!*thrown) { |
| char msg[100]; |
| sprintf(msg, "Parse error at pos=%d", spos); |
| jniThrowException(env, "android/util/TimeFormatException", msg); |
| *thrown = true; |
| } |
| return 0; |
| } |
| } |
| |
| static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected) |
| { |
| jchar c = s[spos]; |
| if (c != expected) { |
| char msg[100]; |
| sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos, |
| expected); |
| jniThrowException(env, "android/util/TimeFormatException", msg); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj) |
| { |
| jsize len = env->GetStringLength(strObj); |
| const jchar *s = env->GetStringChars(strObj, NULL); |
| |
| bool thrown = false; |
| int n; |
| jboolean inUtc = false; |
| |
| if (len < 8) { |
| char msg[100]; |
| sprintf(msg, "String too short -- expected at least 8 characters."); |
| jniThrowException(env, "android/util/TimeFormatException", msg); |
| return false; |
| } |
| |
| // year |
| n = get_char(env, s, 0, 1000, &thrown); |
| n += get_char(env, s, 1, 100, &thrown); |
| n += get_char(env, s, 2, 10, &thrown); |
| n += get_char(env, s, 3, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_yearField, n); |
| |
| // month |
| n = get_char(env, s, 4, 10, &thrown); |
| n += get_char(env, s, 5, 1, &thrown); |
| n--; |
| if (thrown) return false; |
| env->SetIntField(This, g_monField, n); |
| |
| // day of month |
| n = get_char(env, s, 6, 10, &thrown); |
| n += get_char(env, s, 7, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_mdayField, n); |
| |
| if (len > 8) { |
| // T |
| if (!check_char(env, s, 8, 'T')) return false; |
| env->SetBooleanField(This, g_allDayField, JNI_FALSE); |
| |
| // hour |
| n = get_char(env, s, 9, 10, &thrown); |
| n += get_char(env, s, 10, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_hourField, n); |
| |
| // min |
| n = get_char(env, s, 11, 10, &thrown); |
| n += get_char(env, s, 12, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_minField, n); |
| |
| // sec |
| n = get_char(env, s, 13, 10, &thrown); |
| n += get_char(env, s, 14, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_secField, n); |
| |
| if (len > 15) { |
| // Z |
| if (!check_char(env, s, 15, 'Z')) return false; |
| inUtc = true; |
| } |
| } else { |
| env->SetBooleanField(This, g_allDayField, JNI_TRUE); |
| env->SetIntField(This, g_hourField, 0); |
| env->SetIntField(This, g_minField, 0); |
| env->SetIntField(This, g_secField, 0); |
| } |
| |
| env->SetIntField(This, g_wdayField, 0); |
| env->SetIntField(This, g_ydayField, 0); |
| env->SetIntField(This, g_isdstField, -1); |
| env->SetLongField(This, g_gmtoffField, 0); |
| |
| env->ReleaseStringChars(strObj, s); |
| return inUtc; |
| } |
| |
| static jboolean android_text_format_Time_parse3339(JNIEnv* env, |
| jobject This, |
| jstring strObj) |
| { |
| jsize len = env->GetStringLength(strObj); |
| const jchar *s = env->GetStringChars(strObj, NULL); |
| |
| bool thrown = false; |
| int n; |
| jboolean inUtc = false; |
| |
| if (len < 10) { |
| jniThrowException(env, "android/util/TimeFormatException", |
| "Time input is too short; must be at least 10 characters"); |
| return false; |
| } |
| |
| // year |
| n = get_char(env, s, 0, 1000, &thrown); |
| n += get_char(env, s, 1, 100, &thrown); |
| n += get_char(env, s, 2, 10, &thrown); |
| n += get_char(env, s, 3, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_yearField, n); |
| |
| // - |
| if (!check_char(env, s, 4, '-')) return false; |
| |
| // month |
| n = get_char(env, s, 5, 10, &thrown); |
| n += get_char(env, s, 6, 1, &thrown); |
| --n; |
| if (thrown) return false; |
| env->SetIntField(This, g_monField, n); |
| |
| // - |
| if (!check_char(env, s, 7, '-')) return false; |
| |
| // day |
| n = get_char(env, s, 8, 10, &thrown); |
| n += get_char(env, s, 9, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_mdayField, n); |
| |
| if (len >= 19) { |
| // T |
| if (!check_char(env, s, 10, 'T')) return false; |
| |
| env->SetBooleanField(This, g_allDayField, JNI_FALSE); |
| // hour |
| n = get_char(env, s, 11, 10, &thrown); |
| n += get_char(env, s, 12, 1, &thrown); |
| if (thrown) return false; |
| int hour = n; |
| // env->SetIntField(This, g_hourField, n); |
| |
| // : |
| if (!check_char(env, s, 13, ':')) return false; |
| |
| // minute |
| n = get_char(env, s, 14, 10, &thrown); |
| n += get_char(env, s, 15, 1, &thrown); |
| if (thrown) return false; |
| int minute = n; |
| // env->SetIntField(This, g_minField, n); |
| |
| // : |
| if (!check_char(env, s, 16, ':')) return false; |
| |
| // second |
| n = get_char(env, s, 17, 10, &thrown); |
| n += get_char(env, s, 18, 1, &thrown); |
| if (thrown) return false; |
| env->SetIntField(This, g_secField, n); |
| |
| // skip the '.XYZ' -- we don't care about subsecond precision. |
| int tz_index = 19; |
| if (tz_index < len && s[tz_index] == '.') { |
| do { |
| tz_index++; |
| } while (tz_index < len |
| && s[tz_index] >= '0' |
| && s[tz_index] <= '9'); |
| } |
| |
| int offset = 0; |
| if (len > tz_index) { |
| char c = s[tz_index]; |
| |
| // NOTE: the offset is meant to be subtracted to get from local time |
| // to UTC. we therefore use 1 for '-' and -1 for '+'. |
| switch (c) { |
| case 'Z': |
| // Zulu time -- UTC |
| offset = 0; |
| break; |
| case '-': |
| offset = 1; |
| break; |
| case '+': |
| offset = -1; |
| break; |
| default: |
| char msg[100]; |
| sprintf(msg, "Unexpected character 0x%02x at position %d. Expected + or -", |
| c, tz_index); |
| jniThrowException(env, "android/util/TimeFormatException", msg); |
| return false; |
| } |
| inUtc = true; |
| |
| if (offset != 0) { |
| if (len < tz_index + 6) { |
| char msg[100]; |
| sprintf(msg, "Unexpected length; should be %d characters", tz_index + 6); |
| jniThrowException(env, "android/util/TimeFormatException", msg); |
| return false; |
| } |
| |
| // hour |
| n = get_char(env, s, tz_index + 1, 10, &thrown); |
| n += get_char(env, s, tz_index + 2, 1, &thrown); |
| if (thrown) return false; |
| n *= offset; |
| hour += n; |
| |
| // : |
| if (!check_char(env, s, tz_index + 3, ':')) return false; |
| |
| // minute |
| n = get_char(env, s, tz_index + 4, 10, &thrown); |
| n += get_char(env, s, tz_index + 5, 1, &thrown); |
| if (thrown) return false; |
| n *= offset; |
| minute += n; |
| } |
| } |
| env->SetIntField(This, g_hourField, hour); |
| env->SetIntField(This, g_minField, minute); |
| |
| if (offset != 0) { |
| // we need to normalize after applying the hour and minute offsets |
| android_text_format_Time_normalize(env, This, false /* use isdst */); |
| // The timezone is set to UTC in the calling Java code. |
| } |
| } else { |
| env->SetBooleanField(This, g_allDayField, JNI_TRUE); |
| env->SetIntField(This, g_hourField, 0); |
| env->SetIntField(This, g_minField, 0); |
| env->SetIntField(This, g_secField, 0); |
| } |
| |
| env->SetIntField(This, g_wdayField, 0); |
| env->SetIntField(This, g_ydayField, 0); |
| env->SetIntField(This, g_isdstField, -1); |
| env->SetLongField(This, g_gmtoffField, 0); |
| |
| env->ReleaseStringChars(strObj, s); |
| return inUtc; |
| } |
| |
| // ============================================================================ |
| /* |
| * JNI registration. |
| */ |
| static JNINativeMethod gMethods[] = { |
| /* name, signature, funcPtr */ |
| { "normalize", "(Z)J", (void*)android_text_format_Time_normalize }, |
| { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_text_format_Time_switchTimezone }, |
| { "compare", "(Landroid/text/format/Time;Landroid/text/format/Time;)I", (void*)android_text_format_Time_compare }, |
| { "format1", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_text_format_Time_format }, |
| { "format2445", "()Ljava/lang/String;", (void*)android_text_format_Time_format2445 }, |
| { "toString", "()Ljava/lang/String;", (void*)android_text_format_Time_toString }, |
| { "nativeParse", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse }, |
| { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse3339 }, |
| { "setToNow", "()V", (void*)android_text_format_Time_setToNow }, |
| { "toMillis", "(Z)J", (void*)android_text_format_Time_toMillis }, |
| { "set", "(J)V", (void*)android_text_format_Time_set } |
| }; |
| |
| int register_android_text_format_Time(JNIEnv* env) |
| { |
| jclass timeClass = env->FindClass("android/text/format/Time"); |
| |
| g_timeClass = (jclass) env->NewGlobalRef(timeClass); |
| |
| g_allDayField = env->GetFieldID(timeClass, "allDay", "Z"); |
| g_secField = env->GetFieldID(timeClass, "second", "I"); |
| g_minField = env->GetFieldID(timeClass, "minute", "I"); |
| g_hourField = env->GetFieldID(timeClass, "hour", "I"); |
| g_mdayField = env->GetFieldID(timeClass, "monthDay", "I"); |
| g_monField = env->GetFieldID(timeClass, "month", "I"); |
| g_yearField = env->GetFieldID(timeClass, "year", "I"); |
| g_wdayField = env->GetFieldID(timeClass, "weekDay", "I"); |
| g_ydayField = env->GetFieldID(timeClass, "yearDay", "I"); |
| g_isdstField = env->GetFieldID(timeClass, "isDst", "I"); |
| g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J"); |
| g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;"); |
| |
| g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;"); |
| g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;"); |
| g_longStandaloneMonthsField = env->GetStaticFieldID(timeClass, "sLongStandaloneMonths", "[Ljava/lang/String;"); |
| g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;"); |
| g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;"); |
| g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;"); |
| g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;"); |
| g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;"); |
| g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;"); |
| g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;"); |
| g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;"); |
| g_localeField = env->GetStaticFieldID(timeClass, "sLocale", "Ljava/util/Locale;"); |
| |
| return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods)); |
| } |
| |
| }; // namespace android |