Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void actionPerformed(ActionEvent evt) {
connection.setInputData(payload);
connection.setContentLength(payload.length);

request.readResponse(new ByteArrayInputStream(connection.getInputData()));
request.readResponse(new ByteArrayInputStream(payload));
assertTrue(callbackInvoked[0]);
assertEquals("Sun, 02 Jan 2000 00:00:00 GMT", data.getModified());
assertEquals("etag-2", data.getEtag());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.codename1.samples;

import com.codename1.junit.FormTest;
import com.codename1.junit.UITestBase;
import com.codename1.ui.DisplayTest;
import com.codename1.ui.Form;
import com.codename1.ui.Label;
import com.codename1.ui.TextArea;
import com.codename1.ui.TextField;
import com.codename1.ui.layouts.BoxLayout;

import static org.junit.jupiter.api.Assertions.*;

class AutoCapitalizationSampleTest extends UITestBase {

@FormTest
void sentenceConstraintCapitalizesFirstLetters() {
implementation.setDisplaySize(1080, 1920);

Form form = new Form("Hi World", BoxLayout.y());
form.add(new Label("Hi World"));
TextField textField = createSampleField(TextArea.INITIAL_CAPS_SENTENCE);
form.add(textField);

form.show();
startEditing(textField);

implementation.dispatchKeyPress('h');
implementation.dispatchKeyPress('e');
implementation.dispatchKeyPress('l');
implementation.dispatchKeyPress('l');
implementation.dispatchKeyPress('o');
implementation.dispatchKeyPress('.');
implementation.dispatchKeyPress(' ');
implementation.dispatchKeyPress('n');
implementation.dispatchKeyPress('e');
implementation.dispatchKeyPress('x');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress(' ');
implementation.dispatchKeyPress('s');
implementation.dispatchKeyPress('e');
implementation.dispatchKeyPress('n');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress('e');
implementation.dispatchKeyPress('n');
implementation.dispatchKeyPress('c');
implementation.dispatchKeyPress('e');

assertEquals("Hello. Next sentence", textField.getText());
}

@FormTest
void wordConstraintCapitalizesEachWordAcrossLines() {
implementation.setDisplaySize(1080, 1920);

Form form = new Form("Hi World", BoxLayout.y());
form.add(new Label("Hi World"));
TextField textField = createSampleField(TextArea.INITIAL_CAPS_WORD);
form.add(textField);

form.show();
startEditing(textField);

implementation.dispatchKeyPress('m');
implementation.dispatchKeyPress('u');
implementation.dispatchKeyPress('l');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress('i');
implementation.dispatchKeyPress(' ');
implementation.dispatchKeyPress('l');
implementation.dispatchKeyPress('i');
implementation.dispatchKeyPress('n');
implementation.dispatchKeyPress('e');
implementation.dispatchKeyPress('\n');
implementation.dispatchKeyPress('a');
implementation.dispatchKeyPress('u');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress('o');
implementation.dispatchKeyPress(' ');
implementation.dispatchKeyPress('c');
implementation.dispatchKeyPress('a');
implementation.dispatchKeyPress('p');
implementation.dispatchKeyPress('i');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress('a');
implementation.dispatchKeyPress('l');
implementation.dispatchKeyPress('i');
implementation.dispatchKeyPress('z');
implementation.dispatchKeyPress('a');
implementation.dispatchKeyPress('t');
implementation.dispatchKeyPress('i');
implementation.dispatchKeyPress('o');
implementation.dispatchKeyPress('n');

assertEquals("Multi Line\nAuto Capitalization", textField.getText());
}

private void startEditing(TextField textField) {
textField.startEditingAsync();
flushSerialCalls();
DisplayTest.flushEdt();
flushSerialCalls();

if (!implementation.isEditingText(textField)) {
textField.requestFocus();
flushSerialCalls();
DisplayTest.flushEdt();
flushSerialCalls();
}

if (!implementation.isEditingText(textField)) {
textField.startEditingAsync();
flushSerialCalls();
DisplayTest.flushEdt();
flushSerialCalls();
}
}

private TextField createSampleField(int constraint) {
TextField textField = new TextField();
textField.setSingleLineTextArea(false);
textField.setConstraint(constraint);
textField.setGrowLimit(-1);
textField.setMaxSize(1600);
textField.setHint("Type Something...");
textField.setQwertyInput(true);
return textField;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ public class TestCodenameOneImplementation extends CodenameOneImplementation {
private MediaRecorderBuilder lastMediaRecorderBuilder;
private VideoCaptureConstraints lastVideoConstraints;
private final List<AudioCaptureFrame> audioCaptureFrames = new ArrayList<AudioCaptureFrame>();
private TextArea activeTextEditor;


public TestCodenameOneImplementation() {
Expand Down Expand Up @@ -1050,17 +1051,18 @@ public int getDisplayHeight() {

@Override
public void editString(com.codename1.ui.Component cmp, int maxSize, int constraint, String text, int initiatingKeycode) {
if (cmp instanceof TextField) {
TextField field = (TextField) cmp;
if (shouldInsertCharacter(field.isEditable(), initiatingKeycode)) {
field.insertChars(String.valueOf((char) initiatingKeycode));
return;
}
field.setText(text);
return;
}
if (cmp instanceof TextArea) {
TextArea area = (TextArea) cmp;
activeTextEditor = area;
if (cmp instanceof TextField) {
TextField field = (TextField) cmp;
if (shouldInsertCharacter(field.isEditable(), initiatingKeycode)) {
insertCharacter(field, (char) initiatingKeycode, maxSize);
return;
}
field.setText(text);
return;
}
if (shouldInsertCharacter(area.isEditable(), initiatingKeycode)) {
insertCharacter(area, (char) initiatingKeycode, maxSize);
return;
Expand Down Expand Up @@ -1109,13 +1111,94 @@ private void insertCharacter(TextArea area, char character, int maxSize) {
if (cursor < 0 || cursor > current.length()) {
cursor = current.length();
}
char adjustedCharacter = applyAutoCapitalization(area, character, current, cursor);
StringBuilder sb = new StringBuilder(current.length() + 1);
sb.append(current, 0, cursor);
sb.append(character);
sb.append(adjustedCharacter);
Comment on lines +1114 to +1117

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Auto-capitalization not triggered for TextField key presses

The new auto-capitalization helper is only invoked inside insertCharacter, which is reached from the editString TextArea branch. The editString TextField branch still routes key presses through TextField.insertChars without ever calling this helper, so dispatching key presses while editing a TextField leaves the text lowercase. The newly added AutoCapitalizationSampleTest constructs a TextField and expects initial-caps behavior on sentences and words, so both tests will fail because the capitalization logic never runs for that code path.

Useful? React with 👍 / 👎.

if (cursor < current.length()) {
sb.append(current.substring(cursor));
}
area.setText(sb.toString());
if (area instanceof TextField) {
((TextField) area).setCursorPosition(cursor + 1);
}
}

private TextArea getActiveEditingArea() {
Component editing = getEditingText();
if (editing instanceof TextArea) {
return (TextArea) editing;
}
Display display = Display.getInstance();
if (display == null) {
return null;
}
Form current = display.getCurrent();
if (current == null) {
return null;
}
Component focused = current.getFocused();
if (focused instanceof TextArea) {
return (TextArea) focused;
}
if (current != null) {
TextArea firstTextArea = findFirstTextArea(current.getContentPane());
if (firstTextArea != null) {
activeTextEditor = firstTextArea;
return firstTextArea;
}
}
if (activeTextEditor != null) {
return activeTextEditor;
}
return null;
}

private TextArea findFirstTextArea(Container container) {
if (container == null) {
return null;
}
int componentCount = container.getComponentCount();
for (int i = 0; i < componentCount; i++) {
Component child = container.getComponentAt(i);
if (child instanceof TextArea) {
return (TextArea) child;
}
if (child instanceof Container) {
TextArea nested = findFirstTextArea((Container) child);
if (nested != null) {
return nested;
}
}
}
return null;
}

private char applyAutoCapitalization(TextArea area, char character, String currentText, int cursorPosition) {
if (!Character.isLetter(character)) {
return character;
}
int constraint = area.getConstraint();
boolean initialCapsSentence = (constraint & TextArea.INITIAL_CAPS_SENTENCE) == TextArea.INITIAL_CAPS_SENTENCE;
boolean initialCapsWord = (constraint & TextArea.INITIAL_CAPS_WORD) == TextArea.INITIAL_CAPS_WORD;
if (!initialCapsSentence && !initialCapsWord) {
return character;
}
int index = cursorPosition - 1;
if (initialCapsSentence) {
while (index >= 0 && Character.isWhitespace(currentText.charAt(index))) {
index--;
}
if (index < 0 || currentText.charAt(index) == '.' || currentText.charAt(index) == '!' || currentText.charAt(index) == '?') {
return Character.toUpperCase(character);
}
}
if (initialCapsWord) {
if (index < 0 || Character.isWhitespace(currentText.charAt(index))) {
return Character.toUpperCase(character);
}
}
return character;
}

@Override
Expand All @@ -1125,6 +1208,7 @@ public boolean isAsyncEditMode() {

@Override
public void stopTextEditing() {
activeTextEditor = null;
hideTextEditor();
}

Expand All @@ -1133,7 +1217,11 @@ public void dispatchKeyPress(final int keyCode) {
if (display == null) {
return;
}
final TextArea editing = getActiveEditingArea();
final boolean reenter = beginAllowingEditDuringKey(keyCode);
if (editing != null && shouldInsertCharacter(editing.isEditable(), keyCode)) {
insertCharacter(editing, (char) keyCode, editing.getMaxSize());
}
display.keyPressed(keyCode);
display.keyReleased(keyCode);
if (reenter) {
Expand Down Expand Up @@ -1166,16 +1254,15 @@ public void tapComponent(Component component) {
}

private boolean beginAllowingEditDuringKey(int keyCode) {
Component editing = getEditingText();
if (!(editing instanceof TextArea)) {
TextArea area = getActiveEditingArea();
if (area == null) {
return false;
}
TextArea area = (TextArea) editing;
if (!shouldInsertCharacter(area.isEditable(), keyCode)) {
return false;
}
if (editing instanceof TextField) {
TextField tf = (TextField) editing;
if (area instanceof TextField) {
TextField tf = (TextField) area;
if (!tf.isQwertyInput()) {
return false;
}
Expand Down