Skip to content

Commit f4eeed1

Browse files
authored
Merge branch 'master' into fix-spotbugs-switch-defaults-2790825227576484200
2 parents 52c70cf + f0a072a commit f4eeed1

File tree

17 files changed

+3298
-13
lines changed

17 files changed

+3298
-13
lines changed

CodenameOne/src/com/codename1/l10n/SimpleDateFormat.java

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ public class SimpleDateFormat extends DateFormat {
118118
* Pattern character for RFC 822-style timezone.
119119
*/
120120
private static final char TIMEZONE822_LETTER = 'Z';
121+
/**
122+
* Pattern character for ISO 8601 timezone.
123+
*/
124+
private static final char ISO_TIMEZONE_LETTER = 'X';
125+
/**
126+
* Pattern character for week year.
127+
*/
128+
private static final char WEEK_YEAR_LETTER = 'Y';
129+
/**
130+
* Pattern character for day number of week.
131+
*/
132+
private static final char DAY_NUMBER_OF_WEEK_LETTER = 'u';
121133
/**
122134
* Internally used character for literal text.
123135
*/
@@ -141,7 +153,7 @@ public class SimpleDateFormat extends DateFormat {
141153
/**
142154
* Pattern characters recognized by this implementation (same as JDK 1.6).
143155
*/
144-
private static final String PATTERN_LETTERS = "adDEFGHhKkMmsSwWyzZ";
156+
private static final String PATTERN_LETTERS = "adDEFGHhKkMmsSwWyzZXYu";
145157
/**
146158
* TimeZone ID for Greenwich Mean Time
147159
*/
@@ -371,7 +383,24 @@ String format(Date source, StringBuilder toAppendTo) {
371383
toAppendTo.append(leftPad(v / 60, 2));
372384
toAppendTo.append(leftPad(v % 60, 2));
373385
break;
386+
case ISO_TIMEZONE_LETTER:
387+
v = getOffsetInMinutes(calendar, calendar.getTimeZone());
388+
if (v < 0) {
389+
toAppendTo.append(SIGN_NEGATIVE);
390+
v = -v;
391+
} else {
392+
toAppendTo.append(SIGN_POSITIVE);
393+
}
394+
toAppendTo.append(leftPad(v / 60, 2));
395+
if (len >= 2) {
396+
if (len == 3) {
397+
toAppendTo.append(':');
398+
}
399+
toAppendTo.append(leftPad(v % 60, 2));
400+
}
401+
break;
374402
case YEAR_LETTER:
403+
case WEEK_YEAR_LETTER:
375404
v = calendar.get(Calendar.YEAR);
376405
if (len == 2) {
377406
v %= 100;
@@ -441,6 +470,10 @@ String format(Date source, StringBuilder toAppendTo) {
441470
v = calendar.get(DAY_OF_WEEK_IN_MONTH);
442471
toAppendTo.append(leftPad(v, len));
443472
break;
473+
case DAY_NUMBER_OF_WEEK_LETTER:
474+
v = ((calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7) + 1;
475+
toAppendTo.append(leftPad(v, len));
476+
break;
444477
default:
445478
break;
446479
}
@@ -517,6 +550,7 @@ public Date parse(String source) throws ParseException {
517550
break;
518551
case TIMEZONE_LETTER:
519552
case TIMEZONE822_LETTER:
553+
case ISO_TIMEZONE_LETTER:
520554
s = readTimeZone(source, startIndex);
521555
TimeZoneResult res = new TimeZoneResult();
522556
if (s == null || (v = parseTimeZone(s, startIndex, res)) == -1) {
@@ -527,6 +561,7 @@ public Date parse(String source) throws ParseException {
527561
tzMinutes = ((tzMinutes == -1) ? 0 : tzMinutes) + v;
528562
break;
529563
case YEAR_LETTER:
564+
case WEEK_YEAR_LETTER:
530565
s = readNumber(source, startIndex, token, adjacent);
531566
calendar.set(Calendar.YEAR, parseYear(s, token, startIndex));
532567
break;
@@ -574,6 +609,14 @@ public Date parse(String source) throws ParseException {
574609
calendar.set(DAY_OF_WEEK_IN_MONTH,
575610
parseNumber(s, startIndex, "day of week in month", -5, 5));
576611
break;
612+
case DAY_NUMBER_OF_WEEK_LETTER:
613+
s = readNumber(source, startIndex, token, adjacent);
614+
v = parseNumber(s, startIndex, "day number of week", 1, 7);
615+
// Map 1(Mon)-7(Sun) to Calendar 2(Mon)..1(Sun)
616+
// Mon=1 -> 2. Tue=2 -> 3. ... Sat=6 -> 7. Sun=7 -> 1.
617+
// v % 7 + 1
618+
calendar.set(Calendar.DAY_OF_WEEK, (v % 7) + 1);
619+
break;
577620
default:
578621
break;
579622
}
@@ -1190,14 +1233,27 @@ List<String> parseDatePattern(String pattern) {
11901233
char ch = pattern.charAt(i);
11911234
// Handle literal text enclosed in quotes
11921235
if (ch == EXPLICIT_LITERAL) {
1193-
int n = pattern.indexOf(EXPLICIT_LITERAL, i + 1);
1194-
if (n != -1) {
1195-
if (tmp != null) {
1196-
tokens.add(tmp.charAt(0) + tmp);
1197-
tmp = null;
1236+
if (tmp != null) {
1237+
tokens.add(tmp.charAt(0) + tmp);
1238+
tmp = null;
1239+
}
1240+
StringBuilder sb = new StringBuilder();
1241+
int n = i + 1;
1242+
while (n < plen) {
1243+
char c = pattern.charAt(n);
1244+
if (c == EXPLICIT_LITERAL) {
1245+
if (n + 1 < plen && pattern.charAt(n + 1) == EXPLICIT_LITERAL) {
1246+
sb.append(EXPLICIT_LITERAL);
1247+
n += 2;
1248+
continue;
1249+
} else {
1250+
break;
1251+
}
11981252
}
1199-
tokens.add(LITERAL_LETTER + pattern.substring(i + 1, n));
1253+
sb.append(c);
1254+
n++;
12001255
}
1256+
tokens.add(LITERAL_LETTER + sb.toString());
12011257
i = n;
12021258
continue;
12031259
}
@@ -1212,7 +1268,7 @@ List<String> parseDatePattern(String pattern) {
12121268
int n;
12131269
for (n = i; n < plen; n++) {
12141270
ch = pattern.charAt(n);
1215-
if (PATTERN_LETTERS.indexOf(ch) != -1) {
1271+
if (PATTERN_LETTERS.indexOf(ch) != -1 || ch == EXPLICIT_LITERAL) {
12161272
break;
12171273
}
12181274
if (isAlpha(ch)) {

CodenameOne/src/com/codename1/ui/InfiniteContainer.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,17 @@ public void run() {
124124
}
125125

126126
void refreshImpl() {
127+
if (requestingResults) {
128+
return;
129+
}
127130
requestingResults = true;
128-
Component[] components = fetchComponents(0, amount);
131+
Component[] components;
132+
try {
133+
components = fetchComponents(0, amount);
134+
} catch(RuntimeException err) {
135+
requestingResults = false;
136+
throw err;
137+
}
129138
if (components == null) {
130139
components = new Component[0];
131140
}

Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6977,6 +6977,7 @@ public void sendMessage(String[] recipients, String subject, Message msg) {
69776977
}
69786978
if (msg.getMimeType().equals(Message.MIME_HTML)) {
69796979
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, Html.fromHtml(msg.getContent()));
6980+
emailIntent.putExtra("android.intent.extra.HTML_TEXT", msg.getContent());
69806981
}else{
69816982
/*
69826983
// Attempted this workaround to fix the ClassCastException that occurs on android when

maven/core-unittests/src/test/java/com/codename1/l10n/SimpleDateFormatTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,58 @@ void cloneCopiesPatternAndSymbols() {
133133
assertSame(symbols, clone.getDateFormatSymbols());
134134
}
135135

136+
@Test
137+
void testQuotedStringLiteral() {
138+
// "formats like yyyy.MM.dd G 'at' HH:mm:ss z yield illegal argument exception on the t char."
139+
assertDoesNotThrow(() -> {
140+
new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
141+
}, "Should not throw exception for quoted literal 'at'");
142+
}
143+
144+
@Test
145+
void testEscapedSingleQuoteFormat() {
146+
// "Also formats like: hh 'o''clock' yield exception for the c char."
147+
SimpleDateFormat sdf = new SimpleDateFormat("hh 'o''clock'");
148+
Calendar cal = Calendar.getInstance();
149+
cal.set(Calendar.HOUR, 5);
150+
String result = sdf.format(cal.getTime());
151+
// Expected: 05 o'clock
152+
assertTrue(result.contains("o'clock"), "Should contain single quote: " + result);
153+
}
154+
155+
@Test
156+
void testXXXFormat() {
157+
// "yyyy-MM-dd'T'HH:mm:ss.SSSXXX (exception for X char, recent API level prerequisite)"
158+
assertDoesNotThrow(() -> {
159+
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
160+
}, "Should not throw exception for XXX format");
161+
162+
SimpleDateFormat sdf = new SimpleDateFormat("XXX");
163+
// We cannot reliably test exact timezone string without controlling default timezone,
164+
// but we can check it doesn't crash and produces something reasonable.
165+
String result = sdf.format(new Date());
166+
assertNotNull(result);
167+
assertFalse(result.isEmpty());
168+
}
169+
170+
@Test
171+
void testYYYYAnduFormat() {
172+
// "YYYY-'W'ww-u (exception for Y char)"
173+
assertDoesNotThrow(() -> {
174+
new SimpleDateFormat("YYYY-'W'ww-u");
175+
}, "Should not throw exception for YYYY and u format");
176+
177+
SimpleDateFormat sdf = new SimpleDateFormat("u");
178+
Calendar cal = Calendar.getInstance();
179+
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
180+
String result = sdf.format(cal.getTime());
181+
assertEquals("1", result, "Monday should be 1");
182+
183+
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
184+
result = sdf.format(cal.getTime());
185+
assertEquals("7", result, "Sunday should be 7");
186+
}
187+
136188
private static class StubL10NManager extends L10NManager {
137189
StubL10NManager() {
138190
super("en", "US");

vm/ByteCodeTranslator/src/cn1_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ struct ThreadLocalData {
789789
char* utf8Buffer;
790790
int utf8BufferSize;
791791
JAVA_BOOLEAN threadKilled; // we don't expect to see this in the GC
792+
JAVA_BOOLEAN interrupted;
792793
};
793794

794795
//#define BLOCK_FOR_GC() while(threadStateData->threadBlockedByGC) { usleep(500); }

vm/ByteCodeTranslator/src/nativeMethods.m

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,7 @@ JAVA_INT java_lang_Object_hashCode___R_int(CODENAME_ONE_THREAD_STATE, JAVA_OBJEC
10901090
i->threadBlockedByGC = JAVA_FALSE;
10911091
i->threadActive = JAVA_FALSE;
10921092
i->threadKilled = JAVA_FALSE;
1093+
i->interrupted = JAVA_FALSE;
10931094

10941095
i->currentThreadObject = 0;
10951096

@@ -1461,6 +1462,40 @@ JAVA_LONG java_lang_Thread_getNativeThreadId___R_long(CODENAME_ONE_THREAD_STATE)
14611462
return currentThreadId();
14621463
}
14631464

1465+
JAVA_VOID java_lang_Thread_interrupt0__(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT me) {
1466+
lockCriticalSection();
1467+
for(int i=0; i<NUMBER_OF_SUPPORTED_THREADS; i++) {
1468+
struct ThreadLocalData* d = allThreads[i];
1469+
if(d && d->currentThreadObject == me) {
1470+
d->interrupted = JAVA_TRUE;
1471+
break;
1472+
}
1473+
}
1474+
unlockCriticalSection();
1475+
}
1476+
1477+
JAVA_BOOLEAN java_lang_Thread_isInterrupted___boolean_R_boolean(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT me, JAVA_BOOLEAN clear) {
1478+
JAVA_BOOLEAN ret = JAVA_FALSE;
1479+
// optimization: checking current thread
1480+
if(threadStateData->currentThreadObject == me) {
1481+
ret = threadStateData->interrupted;
1482+
if(clear) threadStateData->interrupted = JAVA_FALSE;
1483+
return ret;
1484+
}
1485+
1486+
lockCriticalSection();
1487+
for(int i=0; i<NUMBER_OF_SUPPORTED_THREADS; i++) {
1488+
struct ThreadLocalData* d = allThreads[i];
1489+
if(d && d->currentThreadObject == me) {
1490+
ret = d->interrupted;
1491+
if(clear) d->interrupted = JAVA_FALSE;
1492+
break;
1493+
}
1494+
}
1495+
unlockCriticalSection();
1496+
return ret;
1497+
}
1498+
14641499
JAVA_DOUBLE java_lang_StringToReal_parseDblImpl___java_lang_String_int_R_double(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT s, JAVA_INT e) {
14651500
int length = java_lang_String_length___R_int(threadStateData, s);
14661501
JAVA_ARRAY arrayData = (JAVA_ARRAY)java_lang_String_toCharNoCopy___R_char_1ARRAY(threadStateData, s);

vm/JavaAPI/src/java/lang/Thread.java

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,21 @@ public final int getPriority(){
122122
* Interrupts this thread. In an implementation conforming to the CLDC Specification, this operation is not required to cancel or clean up any pending I/O operations that the thread may be waiting for.
123123
*/
124124
public void interrupt(){
125+
interrupt0();
125126
}
126127

128+
private native void interrupt0();
129+
130+
public static boolean interrupted() {
131+
return currentThread().isInterrupted(true);
132+
}
133+
134+
public boolean isInterrupted() {
135+
return isInterrupted(false);
136+
}
137+
138+
private native boolean isInterrupted(boolean clearInterrupted);
139+
127140
/**
128141
* Tests if this thread is alive. A thread is alive if it has been started and has not yet died.
129142
*/
@@ -135,12 +148,46 @@ public final boolean isAlive(){
135148
* Waits for this thread to die.
136149
*/
137150
public final void join() throws java.lang.InterruptedException{
138-
// not very efficient but we don't use this method much...
139-
while(alive) {
140-
sleep(30);
151+
join(0);
152+
}
153+
154+
public final synchronized void join(long millis) throws java.lang.InterruptedException {
155+
long base = System.currentTimeMillis();
156+
long now = 0;
157+
158+
if (millis < 0) {
159+
throw new IllegalArgumentException("timeout value is negative");
160+
}
161+
162+
if (millis == 0) {
163+
while (isAlive()) {
164+
wait(0);
165+
}
166+
} else {
167+
while (isAlive()) {
168+
long delay = millis - now;
169+
if (delay <= 0) {
170+
break;
171+
}
172+
wait(delay);
173+
now = System.currentTimeMillis() - base;
174+
}
141175
}
142176
}
143177

178+
public final synchronized void join(long millis, int nanos) throws java.lang.InterruptedException {
179+
if (millis < 0) {
180+
throw new IllegalArgumentException("timeout value is negative");
181+
}
182+
if (nanos < 0 || nanos > 999999) {
183+
throw new IllegalArgumentException("nanosecond timeout value out of range");
184+
}
185+
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
186+
millis++;
187+
}
188+
join(millis);
189+
}
190+
144191
/**
145192
* Invoked from native code...
146193
*/
@@ -155,7 +202,10 @@ private void runImpl(long tid) {
155202
t.printStackTrace();
156203
}
157204
activeThreads--;
158-
alive = false;
205+
synchronized(this) {
206+
alive = false;
207+
notifyAll();
208+
}
159209
}
160210

161211
/**
@@ -183,6 +233,19 @@ public final void setPriority(int newPriority){
183233
*/
184234
public static native void sleep(long millis) throws java.lang.InterruptedException;
185235

236+
public static void sleep(long millis, int nanos) throws java.lang.InterruptedException {
237+
if (millis < 0) {
238+
throw new IllegalArgumentException("timeout value is negative");
239+
}
240+
if (nanos < 0 || nanos > 999999) {
241+
throw new IllegalArgumentException("nanosecond timeout value out of range");
242+
}
243+
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
244+
millis++;
245+
}
246+
sleep(millis);
247+
}
248+
186249
/**
187250
* Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
188251
* The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).

0 commit comments

Comments
 (0)