LAMW (solved) how to prevent location mocking / fake gps on LAMW lazarus / 43-Android ---------------------------------------------------------------------- Mongkey · 2021-08-19 10:58 This is java article i've got, i knew it depreciated on API >25, but it very interesting. https://www.programcreek.com/java-api-examples/?class=android.telephon y.TelephonyManager&method=getAllCellInfo Since i am very beginner on java, i cant implement it, because the return value like tstring. ---------------------------------------------------------------------- engkin · 2021-08-19 14:00 I think this is a Pascal problem. Any Java object is simply translated as a pointer: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit And_jni;...type....     jobject=pointer; including jList. While, up to this point, it might be eaiser to solve problems on the Java side, I believe the proper way is to move the problem to the Pascal side. ---------------------------------------------------------------------- engkin · 2021-08-19 14:05 For instance android.telephony.TelephonyManager is something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit uATTelephonyManager; {$mode delphi} interface uses  Classes, SysUtils, And_jni, AndroidWidget,  Laz_And_Controls, uAndroidCommon; type   { jTelephonyManager }   jTelephonyManager=class(jCommon)  protected    const CClassPath:string='android/telephony/TelephonyManager';  protected    {Shared by *all* jTelephonyManager instances}    FjClass:jObject;static;    FInitialized:boolean;static;    //MethodId fields    jMethodId_getPhoneCount:jmethodID;static;    jMethodId_createForSubscriptionId:jmethodID;static;    jMethodId_getDeviceSoftwareVersion:jmethodID;static;    jMethodId_getDeviceId1:jmethodID;static;    jMethodId_getDeviceId2:jmethodID;static;    jMethodId_getCellLocation:jmethodID;static;    jMethodId_getNeighboringCellInfo:jmethodID;static;    jMethodId_getPhoneType:jmethodID;static;    jMethodId_getNetworkOperatorName:jmethodID;static;    jMethodId_getNetworkOperator:jmethodID;static;    jMethodId_isNetworkRoaming:jmethodID;static;    jMethodId_getNetworkCountryIso:jmethodID;static;    jMethodId_getNetworkType:jmethodID;static;    jMethodId_getDataNetworkType:jmethodID;static;    jMethodId_getVoiceNetworkType:jmethodID;static;    jMethodId_hasIccCard:jmethodID;static;    jMethodId_getSimState:jmethodID;static;    jMethodId_getSimOperator:jmethodID;static;    jMethodId_getSimOperatorName:jmethodID;static;    jMethodId_getSimCountryIso:jmethodID;static;    jMethodId_getSimSerialNumber:jmethodID;static;    jMethodId_getSubscriberId:jmethodID;static;    jMethodId_getGroupIdLevel1:jmethodID;static;    jMethodId_getLine1Number:jmethodID;static;    jMethodId_setLine1NumberForDisplay:jmethodID;static;    jMethodId_getVoiceMailNumber:jmethodID;static;    jMethodId_setVoiceMailNumber:jmethodID;static;    jMethodId_getVoiceMailAlphaTag:jmethodID;static;    jMethodId_getCallState:jmethodID;static;    jMethodId_getDataActivity:jmethodID;static;    jMethodId_getDataState:jmethodID;static;    jMethodId_listen:jmethodID;static;    jMethodId_isVoiceCapable:jmethodID;static;    jMethodId_isSmsCapable:jmethodID;static;    jMethodId_getAllCellInfo:jmethodID;static;    jMethodId_getMmsUserAgent:jmethodID;static;    jMethodId_getMmsUAProfUrl:jmethodID;static;    jMethodId_iccOpenLogicalChannel:jmethodID;static;    jMethodId_iccCloseLogicalChannel:jmethodID;static;    jMethodId_iccTransmitApduLogicalChannel:jmethodID;static;    jMethodId_iccTransmitApduBasicChannel:jmethodID;static;    jMethodId_iccExchangeSimIO:jmethodID;static;    jMethodId_sendEnvelopeWithStatus:jmethodID;static;    jMethodId_getIccAuthentication:jmethodID;static;    jMethodId_setPreferredNetworkTypeToGlobal:jmethodID;static;    jMethodId_hasCarrierPrivileges:jmethodID;static;    jMethodId_setOperatorBrandOverride:jmethodID;static;    jMethodId_canChangeDtmfToneLength:jmethodID;static;    jMethodId_isWorldPhone:jmethodID;static;    jMethodId_isTtyModeSupported:jmethodID;static;    jMethodId_isHearingAidCompatibilitySupported:jmethodID;static;    jMethodId_getVoicemailRingtoneUri:jmethodID;static;    jMethodId_isVoicemailVibrationEnabled:jmethodID;static;  protected    class function get_jClass:jobject;override;    class procedure get_jIDs;override;  public    constructor Create(AjObject:jObject=nil);overload;    class procedure Init;  public    //Procs    function getPhoneCount:jint;    function createForSubscriptionId(_subId:jint):jobject;    function getDeviceSoftwareVersion:String;    function getDeviceId:String;overload;    function getDeviceId(_slotId:jint):String;overload;    function getCellLocation:jobject;    function getNeighboringCellInfo:jobject;  function getPhoneType:jint;    function getNetworkOperatorName:String;    function getNetworkOperator:String;    function isNetworkRoaming:boolean;    function getNetworkCountryIso:String;    function getNetworkType:jint;    function getDataNetworkType:jint;    function getVoiceNetworkType:jint;    function hasIccCard:boolean;    function getSimState:jint;    function getSimOperator:String;    function getSimOperatorName:String;    function getSimCountryIso:String;    function getSimSerialNumber:String;    function getSubscriberId:String;    function getGroupIdLevel1:String;    function getLine1Number:String;    function setLine1NumberForDisplay(_alphaTag:String;_number:String):boolean;    function getVoiceMailNumber:String;    function setVoiceMailNumber(_alphaTag:String;_number:String):boolean;    function getVoiceMailAlphaTag:String;    function getCallState:jint;  function getDataActivity:jint;    function getDataState:jint;    procedure listen(_listener:jobject;_events:jint);    function isVoiceCapable:boolean;    function isSmsCapable:boolean;    function getAllCellInfo:jobject;    function getMmsUserAgent:String;    function getMmsUAProfUrl:String;    function iccOpenLogicalChannel(_AID:String):jobject;    function iccCloseLogicalChannel(_channel:jint):boolean;    function iccTransmit ApduLogicalChannel(_channel:jint;_cla:jint;_instruction:jint;_p1:jint; _p2:jint;_p3:jint;_data:String):String;    function iccTransmitApduBas icChannel(_cla:jint;_instruction:jint;_p1:jint;_p2:jint;_p3:jint;_data :String):String;    function iccExchangeSimIO(_fileID:jint;_command:ji nt;_p1:jint;_p2:jint;_p3:jint;_filePath:String):jbyte;    function sendEnvelopeWithStatus(_content:String):String;    function getIccAuth entication(_appType:jint;_authType:jint;_data:String):String;    function setPreferredNetworkTypeToGlobal:boolean;    function hasCarrierPrivileges:boolean;    function setOperatorBrandOverride(_brand:String):boolean;    function canChangeDtmfToneLength:boolean;    function isWorldPhone:boolean;    function isTtyModeSupported:boolean;    function isHearingAidCompatibilitySupported:boolean;    function getVoicemailRingtoneUri(_accountHandle:jobject):jobject;    function isVoicemailVibrationEnabled(_accountHandle:jobject):boolean;  end; implementation { jTelephonyManager } constructor jTelephonyManager.Create(AjObject:jObject);begin  inherited Create(AjObject);end; ...//code was removed to please the forum post limit :(  This code is machine generated. For now, it ignores exceptions which should be fixed. You are interested in: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     function getAllCellInfo:jobject; Notice how it returns jobject. Now we need another class for java.util.List: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit uJUList; {$mode delphi} interface uses  Classes, SysUtils, And_jni, AndroidWidget,  Laz_And_Controls, uAndroidCommon; type   { jList }   jList=class(jCommon)  protected    const CClassPath:string='java/util/List';  protected    {Shared by *all* jList instances}    FjClass:jObject;static;    FInitialized:boolean;static;    //MethodId fields    jMethodId_size:jmethodID;static;    jMethodId_isEmpty:jmethodID;static;    jMethodId_contains:jmethodID;static;    jMethodId_toArray1:jmethodID;static;    jMethodId_toArray2:jmethodID;static;    jMethodId_remove:jmethodID;static;    jMethodId_addAll:jmethodID;static;    jMethodId_removeAll:jmethodID;static;    jMethodId_clear:jmethodID;static;    jMethodId_equals:jmethodID;static;    jMethodId_get:jmethodID;static;    jMethodId_add:jmethodID;static;    jMethodId_indexOf:jmethodID;static;    jMethodId_listIterator1:jmethodID;static;    jMethodId_listIterator2:jmethodID;static;  protected    class function get_jClass:jobject;override;    class procedure get_jIDs;override;  public    constructor Create(AjObject:jObject=nil);overload;    class procedure Init;  public    //Procs    function size:jint;    function isEmpty:boolean;    function contains(__Param1:jobject):boolean;    function toArray:jobject;overload;    function toArray(__Param2:jobject):jobject;overload;    function remove(__Param1:jobject):boolean;    function addAll(__Param1:jobject):boolean;    function removeAll(__Param1:jobject):boolean;    procedure clear;    function equals(__Param1:jobject):boolean;    function get(__Param1:jint):jobject;    procedure add(__Param1:jint;__Param2:jobject);    function indexOf(__Param1:jobject):jint;    function listIterator:jobject;overload;    function listIterator(__Param1:jint):jobject;overload;  end; implementation { jList } constructor jList.Create(AjObject:jObject);begin  inherited Create(AjObject);end;...//code is cut to please the forum editor  Just like the previous code, this was machine generated. In theory, you take the jobject from getAllCellInfo and pass it to jList.Create jList should give you access to its items which are of type CellInfo, so we need a third class: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit uATCellInfo; {$mode delphi} interface uses  Classes, SysUtils, And_jni, AndroidWidget,  Laz_And_Controls, uAndroidCommon; type   { jCellInfo }   jCellInfo=class(jCommon)  protected    const CClassPath:string='android/telephony/CellInfo';  protected    {Shared by *all* jCellInfo instances}    FjClass:jObject;static;    FInitialized:boolean;static;    //MethodId fields    jMethodId_isRegistered:jmethodID;static;    jMethodId_getTimeStamp:jmethodID;static;    jMethodId_hashCode:jmethodID;static;    jMethodId_equals:jmethodID;static;    jMethodId_toString:jmethodID;static;    jMethodId_describeContents:jmethodID;static;    jMethodId_writeToParcel:jmethodID;static;  protected    class function get_jClass:jobject;override;    class procedure get_jIDs;override;  public    constructor Create(AjObject:jObject=nil);overload;    class procedure Init;  public    //Procs    function isRegistered:boolean;  function getTimeStamp:jlong;    function hashCode:jint;    function equals(_other:jobject):boolean;    function toString:String;    function describeContents:jint;    procedure writeToParcel(__Param1:jobject;__Param2:jint);  end; implementation { jCellInfo } constructor jCellInfo.Create(AjObject:jObject);begin  inherited Create(AjObject);end; class procedure jCellInfo.Init;var  LjClass:jobject;begin  if not FInitialized then  begin    LjClass:=Get_jClassLocalRef(CClassPath);    FjClass:=Get_jObjGlobalRef(LjClass);    Delete_jLocalRef(LjClass);    get_jIDs;    FInitialized:=True;  end;end; class function jCellInfo.get_jClass:jobject;begin  Result:=FjClass;end; class procedure jCellInfo.get_jIDs;begin  jMethodId_isRegistered:=Get_jMethodID(FjClass,'isRegistered','()Z');  jMethodId_getTimeStamp:=Get_jMethodID(FjClass,'getTimeStamp','()J');  jMethodId_hashCode:=Get_jMethodID(FjClass,'hashCode','()I');  jMethodI d_equals:=Get_jMethodID(FjClass,'equals','(Ljava/lang/Object;)Z');  jM ethodId_toString:=Get_jMethodID(FjClass,'toString','()Ljava/lang/Strin g;');  jMethodId_describeContents:=Get_jMethodID(FjClass,'describeCont ents','()I');  jMethodId_writeToParcel:=Get_jMethodID(FjClass,'writeTo Parcel','(Landroid/os/Parcel;I)V');end; function jCellInfo.isRegistered:boolean;begin// ()Z  Result:=jmethod_get_boolean(jMethodID_isRegistered);end; function jCellInfo.getTimeStamp:jlong;begin// ()J  Result:=jmethod_get_jlong(jMethodID_getTimeStamp);end; function jCellInfo.hashCode:jint;begin// ()I  Result:=jmethod_get_jint(jMethodID_hashCode);end; function jCellInfo.equals(_other:jobject):boolean;var  jParams:array[0..0] of jvalue absolute _other;begin// (Ljava/lang/Object;)Z  Result:=jmethod_get_booleanA(jMethodId_equals,jParams);end; function jCellInfo.toString:String;begin// ()Ljava/lang/String;  Result:=jmethod_get_String(jMethodID_toString);end; function jCellInfo.describeContents:jint;begin// ()I  Result:=jmethod_get_jint(jMethodID_describeContents);end; procedure jCellInfo.writeToParcel(__Param1:jobject;__Param2:jint);var  jParams:array[0..1] of jvalue;begin// (Landroid/os/Parcel;I)V  jParams[0].l:=__Param1;  jParams[1].i:=__Param2;  jmethod_voidA(jMethodId_writeToParcel,jParams);end; end.  It might be possible to use Pascal generics to make jList more like its counterpart in Java. Anyway, I could be wrong, but this is how I see it. WARNING: This code was not tested. ---------------------------------------------------------------------- Mongkey · 2021-08-19 22:05 Thank you bro! I'll do my best to follow your sample. ---------------------------------------------------------------------- Mongkey · 2021-08-19 23:34 i tried a lot, too much errors, not find symbol ,i dont understand java, its difficult for me  , I wish this attached code functions intact to LAMW jTelephony component, or new component jGeoFencing  I got many fake gps coordinates, may be by retrieving from cell LAC, MNC solving this problem. New candidate -> geofencing sample. Thank you anyway! ---------------------------------------------------------------------- jmpessoa · 2021-08-20 04:51 Done! improved jTelephonyManager component [need tests  and maybe some fix....] [need "android.permission.ACCESS_COARSE_LOCATION"  granted by the user! ]  GetLocationAreaCode()  GetBaseStationId()  GetMobileNetworkCode() GetMobileCountryCode() Thanks you! PS. files changed: "jTelephonyManager.java" "telephonymanager.pas" ---------------------------------------------------------------------- Mongkey · 2021-08-20 05:36 , thanks prof JM, you are the best! Actually i get more 1 solution for this: for API > 18 Code: Java  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i public static boolean isMockLocationOn(Context context) {    if (Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0"))        return false;    else        return true;} ---------------------------------------------------------------------- Mongkey · 2021-08-20 06:29 Working very well on android 10, just tested get cell location, is it compatible for dual sim android? I gonna test it soon! ---------------------------------------------------------------------- Mongkey · 2021-08-21 05:41 GetLocationAreaCode() GetBaseStationId() GetMobileNetworkCode() GetMobileCountryCode() After trying all, all retrieve same value (dual sim, sim1-> but with expiring telco subscription , no card on sim2), yesterday just tried GetLocationAreaCode(), not yet trying 3 others. After inspecting -> working ok for dual sim -> detect on sim2 only, no card on sim1 -> WORK  may be, retrieving same value if the card has expired -> useful for detecting no longer in service telco simcard ---------------------------------------------------------------------- engkin · 2021-08-22 16:10 This took me longer than I like. I kept having stange exception with an "invalid object". I tracked it down to a call in my code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   javContext:=gApp.GetContext();//<---- fails which is: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function jApp.GetContext(): jObject;begin  Result:= jApp_GetContext(Self.Jni.jEnv, Self.Jni.jThis);//<--- this fails!!end; I assumed Self.Jni.jThis is not holding a valid value anymore, so I turned it into a Java global variable reference: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  gThis:jobject;  gContext:jobject; procedure Java_Event_pAppOnCreate(env: PJNIEnv; this: jobject; context:jobject; layout:jobject; intent: jobject);begin  gThis:=env^.NewGlobalRef(env,this);  gContext:=env^.NewGlobalRef(env,context);   gApp.IsAppActivityRecreate := gApp.FInitialized;  gApp.FInitialized := False;  //gApp.Init(env,this,context,layout, intent);  gApp.Init(env,gThis,gContext,layout, intent);end; Surprisingly that was not enough!! then I skipped Self.Jni.jThis and used the global variable gThis directly: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function jApp.GetContext(): jObject;begin  Result:= jApp_GetContext(Self.Jni.jEnv, gThis);end; Now it works: Quote gApp.APILevel: 30 prob: 7 pasContext.TELEPHONY_SERVICE: phone pasList.size: 4 get(0) CellInfo CellInfoLte:{mRegistered=YES .... get(1) CellInfo CellInfoLte:{mRegistered=NO ... get(2) CellInfo CellInfoLte:{mRegistered=NO ... get(3) CellInfo CellInfoLte:{mRegistered=NO ... ---------------------------------------------------------------------- jmpessoa · 2021-08-22 20:29 Quotefunction jApp.GetContext(): jObject; begin   Result:= jApp_GetContext(Self.Jni.jEnv, Self.Jni.jThis);//<--- this fails!! end; You can see in "Laz_And_Controls_Events.pas"  and "Laz_And_Controls.pas" that all  "Java_Event_*"  call has some code like this: Code: [Select]Procedure Java_Event_pOnTimePicker(env: PJNIEnv; this: jobject; Obj: TObject; hourOfDay: integer; minute: integer); begin   gApp.Jni.jEnv := env;          // <----   if this <> nil then gApp.Jni.jThis := this;      // <----   ......   ....... end;  It keeps these global data always "up to date"! the reference is here: https://android-developers.googleblog.com/2011/11/jni-local-reference- changes-in-ics.html Are you "by passing" LAMW code architecture? ---------------------------------------------------------------------- engkin · 2021-08-22 21:40 No, I am not bypassing LAMW's architecture. I am trying to extend it by bringing Java/Android classes to Pascal. As your reference link shows, Java_Event_pAppOnCreate is expected to use env->NewGlobalRef to store its parameters on the Pascal side, otherwise these values become invalid because of the Garbage Collector moving them around. How come you're not following that reference?  I made a simple app with a jButton and jEditText. The button calls javContext:=gApp.GetContext(); That call fails because gApp.Jni.jThis became invalid. Then I used NewGlobalRef as soon as I received the parameters in Java_Event_pAppOnCreate Passing the results to jApp.Init *seemed* not to work, but NOW, thanks to your explanation, I think they got overwritten by LOCAL references again. That explains why it worked when I used gThis directly,  because it holds the GLOBAL reference. If my understanding is correct, there is a bug in LAMW, it should set the members of jApp.Jni once, AND it should use NewGlobalRef for that, AND it should not change them inside Java_Event_* in unit "Laz_And_Controls_Events.pas"  or any other place. Of course, at the end of the app it should delete the global references. ---------------------------------------------------------------------- jmpessoa · 2021-08-22 22:29 So at the moment we are doing different readings of the document..... this code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Procedure Java_Event_pOnTimePicker(env: PJNIEnv; this: jobject; Obj: TObject; hourOfDay: integer; minute: integer);begin   gApp.Jni.jEnv := env;        // <----  if this <> nil then gApp.Jni.jThis := this;      // <----   ......  .......end; is vital for the entire LAMW code architecture ... and yes "gApp" is global, but  properties gApp.Jni.jEnv and  gApp.Jni.jThis  need to be continually updated otherwise we will get "staled"  object reference.... ---------------------------------------------------------------------- engkin · 2021-08-22 23:44 When I said global, I was not talking about Pascal global variables.  I meant Jave global references. These references do not stall, the Garbage Collector doesn't touch them. What you receive in Java_Event_* is Java local references, these local references will stall. If you intend to use them outside these procedures, as in LAMW, you're supposed to turn the Java local references to Java global references. This is what the article you linked is saying, and it is what works on my side. If you are not convinced, can you show me one simple example where my suggestion will not work? ---------------------------------------------------------------------- jmpessoa · 2021-08-23 02:16 Quotecan you show me one simple example where my suggestion ..... From reference: QuoteNow there’s a per-thread local reference table, it’s vital that you only use a JNIEnv* on the right thread. QuoteIf you have a native peer (a long-lived native object corresponding to a Java object, usually created when the Java object is created and destroyed when the Java object’s finalizer runs), you must not stash a jobject in that native object, because it won’t be valid next time you try to use it. (Similar is true of JNIEnv*s. They might be valid if the next native call happens on the same thread, but they won’t be valid otherwise.) and from here: https://developer.android.com/training/articles/perf- jni QuoteThe JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads. Remember that "LAMW Pascal" side/code  talk to "LAMW java" [multi- thread?] side/code.....  So at some time if you comment out these two lines of code: Quote  gApp.Jni.jEnv := env;                             // <----   if this <> nil then gApp.Jni.jThis := this;  // <---  you will get  a staled object reference ..... ---------------------------------------------------------------------- jmpessoa · 2021-08-23 16:07 QuoteI am trying to extend it by bringing Java/Android classes to Pascal. There is a "conceptual" attempt here: "Laz_And_jni_Controls.pas"  and demo "AppTest2" ---------------------------------------------------------------------- engkin · 2021-08-23 20:05 Quote from: jmpessoa on August 23, 2021, 04:16:09 amRemember that "LAMW Pascal" side/code  talk to "LAMW java" [multi-thread?] side/code.....  All I mentioned was for a single thread, and I am leaving JNIEnv out for now. Later both will be included. That's why I asked you for the simplest example. In the simplest case with a single thread and a single activity, any jobject we receive inside events is going to stale by the end of the event. If we need the object outside that event, then we need to turn it into a Java global reference. For now, I can manage without any changes to LAMW. So let's keep LAMW as is. Quote from: jmpessoa on August 23, 2021, 06:07:47 pmThere is a "conceptual" attempt here: "Laz_And_jni_Controls.pas"  and demo "AppTest2" Yes, this is what I want to do. Can you please correct me if I state something not accurate in any of the following: I noticed IDs we get from calling Get_j*ID can be reused and we do not need to call Get_j*ID again for the same member. For instance instead of: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidListView.NotifyDataSetChanged(jAdapter: jObject);var  jClass_arrayAdapter: jClass;  jMethodId_notifyDataSetChanged:  jMethodID;begin  jClass_arrayAdapter:= Get_jClassLocalRef('android/widget/ArrayAdapter');  jMethodId_notifyDataSetChanged:= Get_jMethodID(jClass_arrayAdapter, 'notifyDataSetChanged','()V');  Call_jVoidMethod(jAdapter, jMethodId_notifyDataSetChanged);end; we can write: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidListView.NotifyDataSetChanged(jAdapter: jObject);begin  Call_jVoidMethod(jAdapter, jMethodId_notifyDataSetChanged);end; Assuming jMethodId_notifyDataSetChanged declared as a "static" member of the TAndroidListView and has the correct value. ---------------------------------------------------------------------- engkin · 2021-08-23 20:25 Quote from: jmpessoa on August 23, 2021, 06:07:47 pm QuoteI am trying to extend it by bringing Java/Android classes to Pascal. There is a "conceptual" attempt here: "Laz_And_jni_Controls.pas"  and demo "AppTest2" I just installed this example on my phone, and now I want to know what problems did you face to prevent you from moving in this direction? Asked in a different way, why do you keep adding to the Java part? ---------------------------------------------------------------------- jmpessoa · 2021-08-23 21:38 QuoteI want to know what problems did you face to prevent you from moving in this direction? just absolute lack of time..... QuoteAsked in a different way, why do you keep adding to the Java part? 0) LAMW "GUI" was the way found after experiences/trials [and frustrations] for me and for many others (felipemdc, simonsayz, .... ) 1) Code reuse: thousands of java/android tutorials deliver ready-to- use solutions.... 2) we can embed all the logic (including asynchronous routines, exception handle, ....) in java side and leaving to pascal only the work of making the methods calls and responding to the events ..... making code generation [and use] on the pascal side "clear" and easier. side note 1: yes, it is still possible other approaches in LAMW "GUI" and "fixes" including your suggestion about a global "gThis" but we need a lot of [time and] code refactoring, testing/maturation  otherwise we run the risk of break/stop  everything [legacy] that is working .... side note 2: @loaded is working in another direction:  LAMW "NoGUI" ---------------------------------------------------------------------- loaded · 2021-08-25 12:30 Quote from: jmpessoa on August 23, 2021, 11:38:04 pmside note 2: @loaded is working in another direction:  LAMW "NoGUI" LAMW, The Platform that pushes the limits of the possible. We can't thank enough the legendary developers of LAMW for bringing this masterpiece to us. It's up to your imagination and skills to do what you want with NoGUI... https://youtu.be/SCAOeAN3eU4 In this study, I wanted to show how .so files created with LAMW module can be used in Android Studio. https://youtu.be/gBS0AMrJ50s Also, the CAD application named Polygon, which I wrote with this method; He started running, he will be in the 1st league soon ---------------------------------------------------------------------- Mongkey · 2021-08-27 08:02 Amazing !