• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright 2006, 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 "Log_println"
18 
19 #include <utils/Log.h>
20 #include <utils/String8.h>
21 #include <assert.h>
22 
23 #include "jni.h"
24 #include "utils/misc.h"
25 #include "android_runtime/AndroidRuntime.h"
26 #include "TimeUtils.h"
27 #include <nativehelper/JNIHelp.h>
28 #include <cutils/tztime.h>
29 
30 namespace android {
31 
32 static jfieldID g_allDayField = 0;
33 static jfieldID g_secField = 0;
34 static jfieldID g_minField = 0;
35 static jfieldID g_hourField = 0;
36 static jfieldID g_mdayField = 0;
37 static jfieldID g_monField = 0;
38 static jfieldID g_yearField = 0;
39 static jfieldID g_wdayField = 0;
40 static jfieldID g_ydayField = 0;
41 static jfieldID g_isdstField = 0;
42 static jfieldID g_gmtoffField = 0;
43 static jfieldID g_timezoneField = 0;
44 
45 static jfieldID g_shortMonthsField = 0;
46 static jfieldID g_longMonthsField = 0;
47 static jfieldID g_longStandaloneMonthsField = 0;
48 static jfieldID g_shortWeekdaysField = 0;
49 static jfieldID g_longWeekdaysField = 0;
50 static jfieldID g_timeOnlyFormatField = 0;
51 static jfieldID g_dateOnlyFormatField = 0;
52 static jfieldID g_dateTimeFormatField = 0;
53 static jfieldID g_amField = 0;
54 static jfieldID g_pmField = 0;
55 static jfieldID g_dateCommandField = 0;
56 static jfieldID g_localeField = 0;
57 
58 static jclass g_timeClass = NULL;
59 
java2time(JNIEnv * env,Time * t,jobject o)60 static inline bool java2time(JNIEnv* env, Time* t, jobject o)
61 {
62     t->t.tm_sec = env->GetIntField(o, g_secField);
63     t->t.tm_min = env->GetIntField(o, g_minField);
64     t->t.tm_hour = env->GetIntField(o, g_hourField);
65     t->t.tm_mday = env->GetIntField(o, g_mdayField);
66     t->t.tm_mon = env->GetIntField(o, g_monField);
67     t->t.tm_year = (env->GetIntField(o, g_yearField))-1900;
68     t->t.tm_wday = env->GetIntField(o, g_wdayField);
69     t->t.tm_yday = env->GetIntField(o, g_ydayField);
70     t->t.tm_isdst = env->GetIntField(o, g_isdstField);
71     t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
72     bool allDay = env->GetIntField(o, g_allDayField);
73     if (allDay &&
74 	((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
75         char msg[100];
76 	sprintf(msg, "allDay is true but sec, min, hour are not 0.");
77 	jniThrowException(env, "java/lang/IllegalArgumentException", msg);
78 	return false;
79     }
80     return true;
81 }
82 
time2java(JNIEnv * env,jobject o,const Time & t)83 static inline void time2java(JNIEnv* env, jobject o, const Time &t)
84 {
85     env->SetIntField(o, g_secField, t.t.tm_sec);
86     env->SetIntField(o, g_minField, t.t.tm_min);
87     env->SetIntField(o, g_hourField, t.t.tm_hour);
88     env->SetIntField(o, g_mdayField, t.t.tm_mday);
89     env->SetIntField(o, g_monField, t.t.tm_mon);
90     env->SetIntField(o, g_yearField, t.t.tm_year+1900);
91     env->SetIntField(o, g_wdayField, t.t.tm_wday);
92     env->SetIntField(o, g_ydayField, t.t.tm_yday);
93     env->SetIntField(o, g_isdstField, t.t.tm_isdst);
94     env->SetLongField(o, g_gmtoffField, t.t.tm_gmtoff);
95 }
96 
97 #define ACQUIRE_TIMEZONE(This, t) \
98     jstring timezoneString_##This \
99             = (jstring) env->GetObjectField(This, g_timezoneField); \
100     t.timezone = env->GetStringUTFChars(timezoneString_##This, NULL);
101 
102 #define RELEASE_TIMEZONE(This, t) \
103     env->ReleaseStringUTFChars(timezoneString_##This, t.timezone);
104 
105 
106 // ============================================================================
107 
android_text_format_Time_normalize(JNIEnv * env,jobject This,jboolean ignoreDst)108 static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This,
109                                            jboolean ignoreDst)
110 {
111     Time t;
112     if (!java2time(env, &t, This)) return 0L;
113     ACQUIRE_TIMEZONE(This, t)
114 
115     int64_t result = t.toMillis(ignoreDst != 0);
116 
117     time2java(env, This, t);
118     RELEASE_TIMEZONE(This, t)
119 
120     return result;
121 }
122 
android_text_format_Time_switchTimezone(JNIEnv * env,jobject This,jstring timezoneObject)123 static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This,
124                             jstring timezoneObject)
125 {
126     Time t;
127     if (!java2time(env, &t, This)) return;
128     ACQUIRE_TIMEZONE(This, t)
129 
130     const char* timezone = env->GetStringUTFChars(timezoneObject, NULL);
131 
132     t.switchTimezone(timezone);
133 
134     time2java(env, This, t);
135     env->ReleaseStringUTFChars(timezoneObject, timezone);
136     RELEASE_TIMEZONE(This, t)
137 
138     // we do this here because there's no point in reallocating the string
139     env->SetObjectField(This, g_timezoneField, timezoneObject);
140 }
141 
android_text_format_Time_compare(JNIEnv * env,jobject clazz,jobject aObject,jobject bObject)142 static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz,
143                             jobject aObject, jobject bObject)
144 {
145     Time a, b;
146 
147     if (!java2time(env, &a, aObject)) return 0;
148     ACQUIRE_TIMEZONE(aObject, a)
149 
150     if (!java2time(env, &b, bObject)) return 0;
151     ACQUIRE_TIMEZONE(bObject, b)
152 
153     int result = Time::compare(a, b);
154 
155     RELEASE_TIMEZONE(aObject, a)
156     RELEASE_TIMEZONE(bObject, b)
157 
158     return result;
159 }
160 
android_text_format_Time_format2445(JNIEnv * env,jobject This)161 static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
162 {
163     Time t;
164     if (!java2time(env, &t, This)) return env->NewStringUTF("");
165     bool allDay = env->GetIntField(This, g_allDayField);
166 
167     if (!allDay) {
168         ACQUIRE_TIMEZONE(This, t)
169         bool inUtc = strcmp("UTC", t.timezone) == 0;
170         short buf[16];
171         t.format2445(buf, true);
172         RELEASE_TIMEZONE(This, t)
173         if (inUtc) {
174             // The letter 'Z' is appended to the end so allow for one
175             // more character in the buffer.
176             return env->NewString((jchar*)buf, 16);
177         } else {
178             return env->NewString((jchar*)buf, 15);
179         }
180     } else {
181         short buf[8];
182         t.format2445(buf, false);
183         return env->NewString((jchar*)buf, 8);
184     }
185 }
186 
android_text_format_Time_format(JNIEnv * env,jobject This,jstring formatObject)187 static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
188                             jstring formatObject)
189 {
190     // We only teardown and setup our 'locale' struct and other state
191     // when the Java-side locale changed.  This is safe to do here
192     // without locking because we're always called from Java code
193     // synchronized on the class instance.
194     static jobject js_locale_previous = NULL;
195     static struct strftime_locale locale;
196     static jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
197     static jstring js_standalone_month[12];
198     static jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
199 
200     Time t;
201     if (!java2time(env, &t, This)) return env->NewStringUTF("");
202 
203     jclass timeClass = g_timeClass;
204     jobject js_locale = (jobject) env->GetStaticObjectField(timeClass, g_localeField);
205     if (js_locale_previous != js_locale) {
206         if (js_locale_previous != NULL) {
207             // Free the old one.
208             for (int i = 0; i < 12; i++) {
209                 env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
210                 env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
211                 env->ReleaseStringUTFChars(js_standalone_month[i], locale.standalone_month[i]);
212                 env->DeleteGlobalRef(js_mon[i]);
213                 env->DeleteGlobalRef(js_month[i]);
214                 env->DeleteGlobalRef(js_standalone_month[i]);
215             }
216 
217             for (int i = 0; i < 7; i++) {
218                 env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
219                 env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
220                 env->DeleteGlobalRef(js_wday[i]);
221                 env->DeleteGlobalRef(js_weekday[i]);
222             }
223 
224             env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
225             env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
226             env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
227             env->ReleaseStringUTFChars(js_am, locale.am);
228             env->ReleaseStringUTFChars(js_pm, locale.pm);
229             env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
230             env->DeleteGlobalRef(js_X_fmt);
231             env->DeleteGlobalRef(js_x_fmt);
232             env->DeleteGlobalRef(js_c_fmt);
233             env->DeleteGlobalRef(js_am);
234             env->DeleteGlobalRef(js_pm);
235             env->DeleteGlobalRef(js_date_fmt);
236         }
237         js_locale_previous = js_locale;
238 
239         jobjectArray ja;
240         ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
241         for (int i = 0; i < 12; i++) {
242             js_mon[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
243             locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
244         }
245 
246         ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
247         for (int i = 0; i < 12; i++) {
248             js_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
249             locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
250         }
251 
252         ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longStandaloneMonthsField);
253         for (int i = 0; i < 12; i++) {
254             js_standalone_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
255             locale.standalone_month[i] = env->GetStringUTFChars(js_standalone_month[i], NULL);
256         }
257 
258         ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
259         for (int i = 0; i < 7; i++) {
260             js_wday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
261             locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
262         }
263 
264         ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
265         for (int i = 0; i < 7; i++) {
266             js_weekday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
267             locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
268         }
269 
270         js_X_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
271                                                        timeClass, g_timeOnlyFormatField));
272         locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
273 
274         js_x_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
275                                                        timeClass, g_dateOnlyFormatField));
276         locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
277 
278         js_c_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
279                                                        timeClass, g_dateTimeFormatField));
280         locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
281 
282         js_am = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
283                                                     timeClass, g_amField));
284         locale.am = env->GetStringUTFChars(js_am, NULL);
285 
286         js_pm = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
287                                                     timeClass, g_pmField));
288         locale.pm = env->GetStringUTFChars(js_pm, NULL);
289 
290         js_date_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
291                                                           timeClass, g_dateCommandField));
292         locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
293     }
294 
295     ACQUIRE_TIMEZONE(This, t)
296 
297     const char* format = env->GetStringUTFChars(formatObject, NULL);
298 
299     String8 r = t.format(format, &locale);
300 
301     env->ReleaseStringUTFChars(formatObject, format);
302     RELEASE_TIMEZONE(This, t)
303 
304     return env->NewStringUTF(r.string());
305 }
306 
307 
android_text_format_Time_toString(JNIEnv * env,jobject This)308 static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
309 {
310     Time t;
311     if (!java2time(env, &t, This)) return env->NewStringUTF("");;
312     ACQUIRE_TIMEZONE(This, t)
313 
314     String8 r = t.toString();
315 
316     RELEASE_TIMEZONE(This, t)
317 
318     return env->NewStringUTF(r.string());
319 }
320 
android_text_format_Time_setToNow(JNIEnv * env,jobject This)321 static void android_text_format_Time_setToNow(JNIEnv* env, jobject This)
322 {
323     env->SetBooleanField(This, g_allDayField, JNI_FALSE);
324     Time t;
325     ACQUIRE_TIMEZONE(This, t)
326 
327     t.setToNow();
328 
329     time2java(env, This, t);
330     RELEASE_TIMEZONE(This, t)
331 }
332 
android_text_format_Time_toMillis(JNIEnv * env,jobject This,jboolean ignoreDst)333 static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This,
334                                         jboolean ignoreDst)
335 {
336     Time t;
337     if (!java2time(env, &t, This)) return 0L;
338     ACQUIRE_TIMEZONE(This, t)
339 
340     int64_t result = t.toMillis(ignoreDst != 0);
341 
342     RELEASE_TIMEZONE(This, t)
343 
344     return result;
345 }
346 
android_text_format_Time_set(JNIEnv * env,jobject This,jlong millis)347 static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis)
348 {
349     env->SetBooleanField(This, g_allDayField, JNI_FALSE);
350     Time t;
351     ACQUIRE_TIMEZONE(This, t)
352 
353     t.set(millis);
354 
355     time2java(env, This, t);
356     RELEASE_TIMEZONE(This, t)
357 }
358 
359 
360 // ============================================================================
361 // Just do this here because it's not worth recreating the strings
362 
get_char(JNIEnv * env,const jchar * s,int spos,int mul,bool * thrown)363 static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
364                     bool *thrown)
365 {
366     jchar c = s[spos];
367     if (c >= '0' && c <= '9') {
368         return (c - '0') * mul;
369     } else {
370         if (!*thrown) {
371             char msg[100];
372             sprintf(msg, "Parse error at pos=%d", spos);
373             jniThrowException(env, "android/util/TimeFormatException", msg);
374             *thrown = true;
375         }
376         return 0;
377     }
378 }
379 
check_char(JNIEnv * env,const jchar * s,int spos,jchar expected)380 static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
381 {
382     jchar c = s[spos];
383     if (c != expected) {
384         char msg[100];
385 	sprintf(msg, "Unexpected %c at pos=%d.  Expected %c.", c, spos,
386 		expected);
387 	jniThrowException(env, "android/util/TimeFormatException", msg);
388 	return false;
389     }
390     return true;
391 }
392 
393 
android_text_format_Time_parse(JNIEnv * env,jobject This,jstring strObj)394 static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
395 {
396     jsize len = env->GetStringLength(strObj);
397     const jchar *s = env->GetStringChars(strObj, NULL);
398 
399     bool thrown = false;
400     int n;
401     jboolean inUtc = false;
402 
403     if (len < 8) {
404         char msg[100];
405         sprintf(msg, "String too short -- expected at least 8 characters.");
406 	jniThrowException(env, "android/util/TimeFormatException", msg);
407 	return false;
408     }
409 
410     // year
411     n = get_char(env, s, 0, 1000, &thrown);
412     n += get_char(env, s, 1, 100, &thrown);
413     n += get_char(env, s, 2, 10, &thrown);
414     n += get_char(env, s, 3, 1, &thrown);
415     if (thrown) return false;
416     env->SetIntField(This, g_yearField, n);
417 
418     // month
419     n = get_char(env, s, 4, 10, &thrown);
420     n += get_char(env, s, 5, 1, &thrown);
421     n--;
422     if (thrown) return false;
423     env->SetIntField(This, g_monField, n);
424 
425     // day of month
426     n = get_char(env, s, 6, 10, &thrown);
427     n += get_char(env, s, 7, 1, &thrown);
428     if (thrown) return false;
429     env->SetIntField(This, g_mdayField, n);
430 
431     if (len > 8) {
432         // T
433         if (!check_char(env, s, 8, 'T')) return false;
434         env->SetBooleanField(This, g_allDayField, JNI_FALSE);
435 
436         // hour
437         n = get_char(env, s, 9, 10, &thrown);
438         n += get_char(env, s, 10, 1, &thrown);
439         if (thrown) return false;
440         env->SetIntField(This, g_hourField, n);
441 
442         // min
443         n = get_char(env, s, 11, 10, &thrown);
444         n += get_char(env, s, 12, 1, &thrown);
445         if (thrown) return false;
446         env->SetIntField(This, g_minField, n);
447 
448         // sec
449         n = get_char(env, s, 13, 10, &thrown);
450         n += get_char(env, s, 14, 1, &thrown);
451         if (thrown) return false;
452         env->SetIntField(This, g_secField, n);
453 
454         if (len > 15) {
455             // Z
456             if (!check_char(env, s, 15, 'Z')) return false;
457 	    inUtc = true;
458         }
459     } else {
460         env->SetBooleanField(This, g_allDayField, JNI_TRUE);
461         env->SetIntField(This, g_hourField, 0);
462         env->SetIntField(This, g_minField, 0);
463         env->SetIntField(This, g_secField, 0);
464     }
465 
466     env->SetIntField(This, g_wdayField, 0);
467     env->SetIntField(This, g_ydayField, 0);
468     env->SetIntField(This, g_isdstField, -1);
469     env->SetLongField(This, g_gmtoffField, 0);
470 
471     env->ReleaseStringChars(strObj, s);
472     return inUtc;
473 }
474 
android_text_format_Time_parse3339(JNIEnv * env,jobject This,jstring strObj)475 static jboolean android_text_format_Time_parse3339(JNIEnv* env,
476                                            jobject This,
477                                            jstring strObj)
478 {
479     jsize len = env->GetStringLength(strObj);
480     const jchar *s = env->GetStringChars(strObj, NULL);
481 
482     bool thrown = false;
483     int n;
484     jboolean inUtc = false;
485 
486     // year
487     n = get_char(env, s, 0, 1000, &thrown);
488     n += get_char(env, s, 1, 100, &thrown);
489     n += get_char(env, s, 2, 10, &thrown);
490     n += get_char(env, s, 3, 1, &thrown);
491     if (thrown) return false;
492     env->SetIntField(This, g_yearField, n);
493 
494     // -
495     if (!check_char(env, s, 4, '-')) return false;
496 
497     // month
498     n = get_char(env, s, 5, 10, &thrown);
499     n += get_char(env, s, 6, 1, &thrown);
500     --n;
501     if (thrown) return false;
502     env->SetIntField(This, g_monField, n);
503 
504     // -
505     if (!check_char(env, s, 7, '-')) return false;
506 
507     // day
508     n = get_char(env, s, 8, 10, &thrown);
509     n += get_char(env, s, 9, 1, &thrown);
510     if (thrown) return false;
511     env->SetIntField(This, g_mdayField, n);
512 
513     if (len >= 17) {
514         // T
515         if (!check_char(env, s, 10, 'T')) return false;
516 
517 	env->SetBooleanField(This, g_allDayField, JNI_FALSE);
518         // hour
519         n = get_char(env, s, 11, 10, &thrown);
520         n += get_char(env, s, 12, 1, &thrown);
521         if (thrown) return false;
522 	int hour = n;
523         // env->SetIntField(This, g_hourField, n);
524 
525 	// :
526 	if (!check_char(env, s, 13, ':')) return false;
527 
528 	// minute
529         n = get_char(env, s, 14, 10, &thrown);
530         n += get_char(env, s, 15, 1, &thrown);
531         if (thrown) return false;
532 	int minute = n;
533         // env->SetIntField(This, g_minField, n);
534 
535 	// :
536 	if (!check_char(env, s, 16, ':')) return false;
537 
538 	// second
539         n = get_char(env, s, 17, 10, &thrown);
540         n += get_char(env, s, 18, 1, &thrown);
541         if (thrown) return false;
542         env->SetIntField(This, g_secField, n);
543 
544 	// skip the '.XYZ' -- we don't care about subsecond precision.
545         int offset = 0;
546 	if (len >= 23) {
547 	    char c = s[23];
548 
549 	    // NOTE: the offset is meant to be subtracted to get from local time
550 	    // to UTC.  we therefore use 1 for '-' and -1 for '+'.
551 	    switch (c) {
552 	    case 'Z':
553 	        // Zulu time -- UTC
554 	        offset = 0;
555 		break;
556 	    case '-':
557                 offset = 1;
558 	        break;
559 	    case '+':
560                 offset = -1;
561 	        break;
562 	    default:
563 	        char msg[100];
564 	        sprintf(msg, "Unexpected %c at position 19.  Expected + or -",
565 			c);
566 	        jniThrowException(env, "android/util/TimeFormatException", msg);
567 	        return false;
568 	    }
569             inUtc = true;
570 
571 	    if (offset != 0) {
572 	        // hour
573 	        n = get_char(env, s, 24, 10, &thrown);
574 		n += get_char(env, s, 25, 1, &thrown);
575 		if (thrown) return false;
576 		n *= offset;
577 		hour += n;
578 
579 		// :
580 		if (!check_char(env, s, 26, ':')) return false;
581 
582 		// minute
583 		n = get_char(env, s, 27, 10, &thrown);
584 		n += get_char(env, s, 28, 1, &thrown);
585 		if (thrown) return false;
586 		n *= offset;
587 		minute += n;
588 	    }
589 	}
590 	env->SetIntField(This, g_hourField, hour);
591         env->SetIntField(This, g_minField, minute);
592 
593 	if (offset != 0) {
594 	    // we need to normalize after applying the hour and minute offsets
595 	    android_text_format_Time_normalize(env, This, false /* use isdst */);
596 	    // The timezone is set to UTC in the calling Java code.
597 	}
598     } else {
599 	env->SetBooleanField(This, g_allDayField, JNI_TRUE);
600         env->SetIntField(This, g_hourField, 0);
601         env->SetIntField(This, g_minField, 0);
602         env->SetIntField(This, g_secField, 0);
603     }
604 
605     env->SetIntField(This, g_wdayField, 0);
606     env->SetIntField(This, g_ydayField, 0);
607     env->SetIntField(This, g_isdstField, -1);
608     env->SetLongField(This, g_gmtoffField, 0);
609 
610     env->ReleaseStringChars(strObj, s);
611     return inUtc;
612 }
613 
614 // ============================================================================
615 /*
616  * JNI registration.
617  */
618 static JNINativeMethod gMethods[] = {
619     /* name, signature, funcPtr */
620     { "normalize",               "(Z)J",                                        (void*)android_text_format_Time_normalize },
621     { "switchTimezone",          "(Ljava/lang/String;)V",                       (void*)android_text_format_Time_switchTimezone },
622     { "compare",                 "(Landroid/text/format/Time;Landroid/text/format/Time;)I",     (void*)android_text_format_Time_compare },
623     { "format1",                 "(Ljava/lang/String;)Ljava/lang/String;",      (void*)android_text_format_Time_format },
624     { "format2445",              "()Ljava/lang/String;",                        (void*)android_text_format_Time_format2445 },
625     { "toString",                "()Ljava/lang/String;",                        (void*)android_text_format_Time_toString },
626     { "nativeParse",             "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse },
627     { "nativeParse3339",         "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse3339 },
628     { "setToNow",                "()V",                                         (void*)android_text_format_Time_setToNow },
629     { "toMillis",                "(Z)J",                                        (void*)android_text_format_Time_toMillis },
630     { "set",                     "(J)V",                                        (void*)android_text_format_Time_set }
631 };
632 
register_android_text_format_Time(JNIEnv * env)633 int register_android_text_format_Time(JNIEnv* env)
634 {
635     jclass timeClass = env->FindClass("android/text/format/Time");
636 
637     g_timeClass = (jclass) env->NewGlobalRef(timeClass);
638 
639     g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
640     g_secField = env->GetFieldID(timeClass, "second", "I");
641     g_minField = env->GetFieldID(timeClass, "minute", "I");
642     g_hourField = env->GetFieldID(timeClass, "hour", "I");
643     g_mdayField = env->GetFieldID(timeClass, "monthDay", "I");
644     g_monField = env->GetFieldID(timeClass, "month", "I");
645     g_yearField = env->GetFieldID(timeClass, "year", "I");
646     g_wdayField = env->GetFieldID(timeClass, "weekDay", "I");
647     g_ydayField = env->GetFieldID(timeClass, "yearDay", "I");
648     g_isdstField = env->GetFieldID(timeClass, "isDst", "I");
649     g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J");
650     g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;");
651 
652     g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;");
653     g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;");
654     g_longStandaloneMonthsField = env->GetStaticFieldID(timeClass, "sLongStandaloneMonths", "[Ljava/lang/String;");
655     g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;");
656     g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;");
657     g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;");
658     g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;");
659     g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;");
660     g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
661     g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
662     g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
663     g_localeField = env->GetStaticFieldID(timeClass, "sLocale", "Ljava/util/Locale;");
664 
665     return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
666 }
667 
668 }; // namespace android
669