merge from open-source master
This commit is contained in:
@ -44,11 +44,11 @@ import java.util.Map;
|
||||
* <pre>
|
||||
* <?xml version="1.0" encoding="utf-8"?>
|
||||
* <selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
* <item android:drawable="@drawable/button_normal" /> <!-- default -->
|
||||
* <item android:state_pressed="true"
|
||||
* android:drawable="@drawable/button_pressed" /> <!-- pressed -->
|
||||
* <item android:state_focused="true"
|
||||
* android:drawable="@drawable/button_focused" /> <!-- focused -->
|
||||
* <item android:drawable="@drawable/button_normal" /> <!-- default -->
|
||||
* </selector></pre>
|
||||
*
|
||||
* <p>Save the XML file in your project {@code res/drawable/} folder and then
|
||||
|
@ -382,7 +382,7 @@ 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 %c at pos=%d. Expected %c.", c, spos,
|
||||
sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos,
|
||||
expected);
|
||||
jniThrowException(env, "android/util/TimeFormatException", msg);
|
||||
return false;
|
||||
@ -483,6 +483,12 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
|
||||
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);
|
||||
@ -510,7 +516,7 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
|
||||
if (thrown) return false;
|
||||
env->SetIntField(This, g_mdayField, n);
|
||||
|
||||
if (len >= 17) {
|
||||
if (len >= 19) {
|
||||
// T
|
||||
if (!check_char(env, s, 10, 'T')) return false;
|
||||
|
||||
@ -541,10 +547,19 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
|
||||
if (thrown) return false;
|
||||
env->SetIntField(This, g_secField, n);
|
||||
|
||||
// skip the '.XYZ' -- we don't care about subsecond precision.
|
||||
// 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 >= 23) {
|
||||
char c = s[23];
|
||||
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 '+'.
|
||||
@ -561,27 +576,34 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
|
||||
break;
|
||||
default:
|
||||
char msg[100];
|
||||
sprintf(msg, "Unexpected %c at position 19. Expected + or -",
|
||||
c);
|
||||
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 + 5) {
|
||||
char msg[100];
|
||||
sprintf(msg, "Unexpected length; should be %d characters", tz_index + 5);
|
||||
jniThrowException(env, "android/util/TimeFormatException", msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// hour
|
||||
n = get_char(env, s, 24, 10, &thrown);
|
||||
n += get_char(env, s, 25, 1, &thrown);
|
||||
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, 26, ':')) return false;
|
||||
if (!check_char(env, s, tz_index + 3, ':')) return false;
|
||||
|
||||
// minute
|
||||
n = get_char(env, s, 27, 10, &thrown);
|
||||
n += get_char(env, s, 28, 1, &thrown);
|
||||
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;
|
||||
|
@ -20,6 +20,7 @@ import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.test.suitebuilder.annotation.Suppress;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import android.util.TimeFormatException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -353,6 +354,86 @@ public class TimeTest extends TestCase {
|
||||
// System.out.println("t=" + t);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testParse33390() throws Exception {
|
||||
Time t = new Time(Time.TIMEZONE_UTC);
|
||||
|
||||
t.parse3339("1980-05-23");
|
||||
if (!t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23) {
|
||||
fail("Did not parse all-day date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != 0) {
|
||||
fail("Did not parse timezone-offset-less date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50Z");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != 0) {
|
||||
fail("Did not parse UTC date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50.0Z");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != 0) {
|
||||
fail("Did not parse UTC date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50.12Z");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != 0) {
|
||||
fail("Did not parse UTC date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50.123Z");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != 0) {
|
||||
fail("Did not parse UTC date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50-06:00");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != -6*3600) {
|
||||
fail("Did not parse timezone-offset date correctly");
|
||||
}
|
||||
|
||||
t.parse3339("1980-05-23T09:50:50.123-06:00");
|
||||
if (t.allDay || t.year != 1980 || t.month != 05 || t.monthDay != 23 ||
|
||||
t.hour != 9 || t.minute != 50 || t.second != 50 ||
|
||||
t.gmtoff != -6*3600) {
|
||||
fail("Did not parse timezone-offset date correctly");
|
||||
}
|
||||
|
||||
try {
|
||||
t.parse3339("1980");
|
||||
fail("Did not throw error on truncated input length");
|
||||
} catch (TimeFormatException e) {
|
||||
// Successful
|
||||
}
|
||||
|
||||
try {
|
||||
t.parse3339("1980-05-23T09:50:50.123+");
|
||||
fail("Did not throw error on truncated timezone offset");
|
||||
} catch (TimeFormatException e1) {
|
||||
// Successful
|
||||
}
|
||||
|
||||
try {
|
||||
t.parse3339("1980-05-23T09:50:50.123+05:0");
|
||||
fail("Did not throw error on truncated timezone offset");
|
||||
} catch (TimeFormatException e1) {
|
||||
// Successful
|
||||
}
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testSet0() throws Exception {
|
||||
Time t = new Time(Time.TIMEZONE_UTC);
|
||||
|
Reference in New Issue
Block a user