Jump to content
Borni

Delphi 12.2 TMEMO - indexoutofbounds

Recommended Posts

HI Folks,

with the return key in a tmemo it crahses with the message

java.lang.indexoutofboundsexception

 under Android32/64.


Someone must have noticed this before !!!

 

BR Borni

Share this post


Link to post

What framework, VCL or FMX?

Edited by hsauro

Share this post


Link to post
28 minutes ago, hsauro said:

What framework, VCL or FMX?

Really?

47 minutes ago, Borni said:

under Android32/64.

 

  • Haha 4

Share this post


Link to post
3 hours ago, Borni said:

with the return key in a tmemo it crahses with the message

java.lang.indexoutofboundsexception

 under Android32/64.

A quick test on a Delphi 12.2 blank FMX app with only a TMemo, compiled for Android 64, running on an Android 13 device doesn't show such error.

Maybe test with a blank project to discard issues with your Delphi/Android SDK installation.

  • Like 1

Share this post


Link to post
10 hours ago, Uwe Raabe said:

Really?

 

Oops sorry. Teach me a lesson for posting.

Share this post


Link to post
11 hours ago, alejandro.sawers said:

A quick test on a Delphi 12.2 blank FMX app with only a TMemo, compiled for Android 64, running on an Android 13 device doesn't show such error.

Maybe test with a blank project to discard issues with your Delphi/Android SDK installation.

Nokia 5.4 with Android 12 - > ok

Google Pixel 8 Android 14 -> ok

Samsung S23 Android 14 -> Exception

Galaxy s10+ Android 12 -> Exception

Galaxy s24+ Android 14 -> Exception

Galaxy Tab A Android 7.1.1 -> Exception

 

all samsung devices !

88fcc528-767b-4138-aaaf-3a1b81545a12.jpg

Edited by Borni

Share this post


Link to post

Exception occurs on my A52s as well. To reproduce, write a character and press the Return key. Pressing the Return key on an empty line doesn't trigger the exception.

Share this post


Link to post

Upon closer inspection, it has nothing to do with the Return key, but with the caret position. The bug can be reproduced just by tapping on another line, the only condition is that the current line must have at least one character.
 

Stack trace:

System._DbgExcNotify(int, void*, System.SmallString<(unsigned char)255>*, void*, void*)
System.NotifyReRaise(System.TObject*, void*)($b40000deac336980,$0000006ef3035c10)
System._InternalRaiseAtExcept(System.TObject*, void*, bool)($b40000deac336980,$0000006ef3035c10,false)
System._RaiseExcept(System.TObject*)($b40000deac336980)
System.Internal.Excutils.DoRaiseJNIExceptionCallBack(System.UnicodeString, System.UnicodeString)(??,??)
Androidapi.Jni.HandleJNIException(JNINativeInterface**)($b40000701924bbf0)
Androidapi.Jnimarshal.ExecJNI(void*, void*, void*, Androidapi.Jnimarshal.JNIMethodInvokeData*, Androidapi.Jnimarshal.m128*)($0000007fe4a32218,$0000007fe4a321f8,$0000007fe4a322f0,$0000007fe4a32200,$0000007fe4a32210)
_DispatchToImport
Fmx.Platform.Ui.Android.TTextServiceAndroid.InternalUpdateSelection()($b4000070c92faf10)
Fmx.Platform.Ui.Android.TTextServiceAndroid.SetText(System.UnicodeString)($b4000070c92faf10,??)
Fmx.Text.Texteditor.TTextEditor.UpdateTextInTextService()($b4000070192bc510)
Fmx.Text.Texteditor.TTextEditor.SetCaretPosition(Fmx.Text.TCaretPosition const&)($b4000070192bc510,{Line = 1, Pos = 0})
Fmx.Memo.Style.New.TStyledMemo.MMSetCaretPosition(Fmx.Presentation.Messages.TDispatchMessageWithValue__1<Fmx.Text.TCaretPosition>&)($b4000070e92689d0,{MsgID = 5917, Value = {Line = 1, Pos = 0}})
System.TObject.Dispatch(void*)($b40000dfdc2671e0,$0000007fe4a326d8)
void Fmx.Presentation.Messages.TMessageSender.SendMessage<Fmx.Text.TCaretPosition>(unsigned short, Fmx.Text.TCaretPosition)($b4000070192bf450,5917,{Line = 1, Pos = 0})
Fmx.Memo.TCustomMemoModel.SetCaretPosition(Fmx.Text.TCaretPosition const&)($b4000070192bf450,{Line = 1, Pos = 0})
Fmx.Memo.TCustomMemoModel.InsertAfter(Fmx.Text.TCaretPosition const&, System.UnicodeString, System.Set<Fmx.Text.TInsertOption, (Fmx.Text.TInsertOption)0, (Fmx.Text.TInsertOption)4>)(??,{Line = 0, Pos = 1},??,{__data = "\\U00000006", __basetype = ??})
Fmx.Memo.Style.New.TStyledMemo.KeyDown(unsigned short&, char16_t&, System.Set<System.Classes.TShiftStateItem, (System.Classes.TShiftStateItem)0, (System.Classes.TShiftStateItem)10>)(??,$0000007fe4a32fa2,U+2fa4 U+e4a3 U+007f U+0000 u'\\xe2\\xbe\\xa4',{__data = "", __basetype = ??})
Fmx.Presentation.Style.TStyledPresentation.PMKeyDown(Fmx.Presentation.Messages.TDispatchMessageWithValue__1<Fmx.Controls.Presentation.TKeyInfo>&)($b4000070e92689d0,{MsgID = 1056, Value = {Key = 13, KeyChar = U+0000 u'\\\\0', Shift = {__data = "", __basetype = ??}}})
System.TObject.Dispatch(void*)($b40000dfdc2671e0,$0000007fe4a32fa0)
void Fmx.Presentation.Messages.TMessageSender.SendMessageWithResult<Fmx.Controls.Presentation.TKeyInfo>(unsigned short, Fmx.Controls.Presentation.TKeyInfo&)($b400006fb92f9d80,1056,{Key = 13, KeyChar = U+0000 u'\\\\0', Shift = {__data = "", __basetype = ??}})
Fmx.Controls.Presentation.TPresentedControl.KeyDown(unsigned short&, char16_t&, System.Set<System.Classes.TShiftStateItem, (System.Classes.TShiftStateItem)0, (System.Classes.TShiftStateItem)10>)($b400006f99280520,$0000007fe4a3330a,U+3302 U+e4a3 U+007f U+0000 u'\\xe3\\x8c\\x82',{__data = "", __basetype = ??})
Fmx.Forms.TCommonCustomForm.KeyDown(unsigned short&, char16_t&, System.Set<System.Classes.TShiftStateItem, (System.Classes.TShiftStateItem)0, (System.Classes.TShiftStateItem)10>)($b400006f9927be50,$0000007fe4a3330a,U+3302 U+e4a3 U+007f U+0000 u'\\xe3\\x8c\\x82',{__data = "", __basetype = ??})
Fmx.Platform.Ui.Android.TAndroidTextInputManager.KeyDown(unsigned short&, char16_t&, System.Set<System.Classes.TShiftStateItem, (System.Classes.TShiftStateItem)0, (System.Classes.TShiftStateItem)10>)($b400007009347710,$0000007fe4a3330a,U+3302 U+e4a3 U+007f U+0000 u'\\xe3\\x8c\\x82',{__data = "", __basetype = ??})
Fmx.Platform.Ui.Android.TAndroidTextInputManager.HandleAndroidKeyEvent(AInputEvent*)($b400007009347710,$b40000700939d2a0)
Fmx.Platform.Android.TPlatformAndroid.HandleAndroidInputEvent(Androidapi.Appglue.TAndroidApplicationGlue*, AInputEvent*)($b4000070192be490,$b40000700939d2a0)
Androidapi.Appglue.TAndroidApplicationGlue.InputEventHandler(int, int, void*)
:0000007234A78B74 android::Looper::pollInner(int)
:0000007234A7862C android::Looper::pollOnce(int, int*, int*, void**)
:00000072278C689C ___lldb_unnamed_symbol9344
:000000009D7B6340 ??

 

The TTextEditor.FCaretPosition was updated while TTextService.FCaretPosition wasn't, and the TTextEditor.UpdateTextInTextService gets called before the TTextService receives the position update. The UpdateTextInTextService passes the string of the newly selected line to the TTextService.SetText, which, among other code, does this:

FTextView.setText(StrToJCharSequence(FText), TJTextView_BufferType.JavaClass.EDITABLE);
// In some cases, EditText can reset selection/caret position to 0. So if user removes text via vkBackspace,
// the backspace button in Soft Keyboard can be unpressed automatically.
InternalUpdateSelection;

Judging from the comment, that second line seems like a new addition. Tracing into it, lo and behold:

procedure TTextServiceAndroid.InternalUpdateSelection;
var
  SelStart, SelEnd: Integer;
begin
  if FTextView = nil then
    Exit;

  CalculateSelectionBounds(SelStart, SelEnd);
  if SelEnd - SelStart > 0 then
    FTextView.setSelection(SelStart, SelEnd)
  else
    FTextView.setSelection(CaretPosition.X); // this one gets executed
end;

It uses its non-updated caret position to update the selection.

Edited by havrlisan
typo
  • Like 1

Share this post


Link to post
43 minutes ago, havrlisan said:

in FMX.Platform.UI.Android.pas

Code:
procedure TTextServiceAndroid.InternalUpdateSelection;
var
  SelStart, SelEnd: Integer;
begin
  if FTextView = nil then
    Exit;

  CalculateSelectionBounds(SelStart, SelEnd);
  if SelEnd - SelStart > 0 then
    FTextView.setSelection(SelStart, SelEnd)
  else
    FTextView.setSelection(JCharSequenceToStr(FTextView.getText).length); // the chagnes found by Enri
end;
  • Thanks 1

Share this post


Link to post

Put my hands on a Samsung A12 and can confirm the issue when pressing the return key:

 

5143342333780143308.thumb.jpg.462544128e607a0c91e0c6f8ca63f584.jpg

 

Testing on a Redmi Note 11 doesn't cause the exception, but by @havrlisan's comment it does happen when tapping on the memo to move the caret from a non-empty line to an empty one.

3 hours ago, Borni said:

in FMX.Platform.UI.Android.pas

Code:
procedure TTextServiceAndroid.InternalUpdateSelection;
var
  SelStart, SelEnd: Integer;
begin
  if FTextView = nil then
    Exit;

  CalculateSelectionBounds(SelStart, SelEnd);
  if SelEnd - SelStart > 0 then
    FTextView.setSelection(SelStart, SelEnd)
  else
    FTextView.setSelection(JCharSequenceToStr(FTextView.getText).length); // the chagnes found by Enri
end;

This change seems to solve the issue on both Samsung and non-Samsung devices.

  • Like 2

Share this post


Link to post

Thanks for letting us know about this. I have raised it with the PM team to look at and validate ASAP. FWIW my own personal mobile is a Samsung device.

  • Thanks 1

Share this post


Link to post

Just as a follow-up the workaround posted by @Borni has the side-effect of sending the caret to the end of the line when deleting a character using the soft keyboard, so I ended up changing this:

On 9/19/2024 at 4:47 AM, Borni said:

FTextView.setSelection(JCharSequenceToStr(FTextView.getText).length); // the chagnes found by Enri

To this:

FTextView.setSelection(SelStart);

Additionally there is another exception thrown when moving the caret with selected text to a line with less characters than the current selection (this happens on Samsung and non-Samsung devices alike). To mitigate that I had to add a couple of lines just before the if SelEnd - SelStart > 0 then check (line 1953) in the same procedure:

// Normalize selection indexes
SelStart:=Min(SelStart, JCharSequenceToStr(FTextView.getText).length);
SelEnd:=Min(SelEnd, JCharSequenceToStr(FTextView.getText).length);

 

Share this post


Link to post

In practice

procedure TTextServiceAndroid.InternalUpdateSelection;
var
  SelStart, SelEnd: Integer;
begin
  if FTextView = nil then
    Exit;

  CalculateSelectionBounds(SelStart, SelEnd);

  SelStart := Min(SelStart, JCharSequenceToStr(FTextView.getText).length);
  SelEnd := Min(SelEnd, JCharSequenceToStr(FTextView.getText).length);

  if SelEnd - SelStart > 0 then
    FTextView.setSelection(SelStart, SelEnd)
  else
    FTextView.setSelection(SelStart);
end;

worked in all tests

Share this post


Link to post

I use the TMemo in Android apps a lot, but due to this issue (I suffer from this as well--Galaxy S10+ phone) I've been holding off compiling to Android via 12.2 

 

Does the Inline Patch 1 from 10-17-2024 fix this issue ?

 

As soon as I can, I will be making an HDD image before I proceed to this Inline Patch 1 process. 

 

Edited by JohnLM

Share this post


Link to post
7 hours ago, JohnLM said:

I use the TMemo in Android apps a lot, but due to this issue (I suffer from this as well--Galaxy S10+ phone) I've been holding off compiling to Android via 12.2 

 

Does the Inline Patch 1 from 10-17-2024 fix this issue ?

 

As soon as I can, I will be making an HDD image before I proceed to this Inline Patch 1 process. 

 

It does. You can read the change log here: https://blogs.embarcadero.com/rad-studio-12-2-athens-inline-patch-1-available/

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×