Jump to content

KMarb

Members
  • Content Count

    77
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by KMarb


  1. More discovery... I'm finding I get the same error now with this line:

     

       camera.FocusMode := TFocusMode.AutoFocus;

     

    with some devices and not others.

     

    Not sure it matters but I have the component created as a face camera:

     

    camera := TCameraComponent.Create (nil);
    camera.Kind := FMX.Media.TCameraKind.FrontCamera;

     

    It seems that some models of phone (or some front cameras) +might not allow me to set focusMode at all... is that correct?

     

    Appreciate any thoughts on how to work past this.

     


  2. I just discovered that some cameras can continuously auto focus and some cannot. Trying to set focusMode to ContinuousAutoFocus blows up the app, in an unrecoverable way... The code below never gets to the except statement:

     

    var

      camera : TCameracomponent;

     

      try
        camera.FocusMode := TFocusMode.ContinuousAutoFocus;
      except
        camera.FocusMode := TFocusMode.AutoFocus;
      end;

     

    is there a way to query the camera to find if it supports ContinuousAutoFocus? Or how to make use of continuous auto focus when available?

     

    Keith


  3. 18 hours ago, Dave Nottage said:

    It seems you may not have included the vision jars in your project, as per the readme.

     

    Pretty sure I'm good with that step:

    image.png.83965134a7ee660a6349db4f73296ce2.png

     

    image.png.0eca1fdae5d4dfb1f90a7eb5c73dde29.png

     

      

    One odd thing... I can add the two vision jars to 64-bit android but not 32-bit. I'm only testing in 64-bit right now, but will need 32-bit to work as well.

     

    I had some success with scanning a few days ago, so I don't think it is my search path, but here is that:

     

    image.png.8ed5dbcf4ba9eb7d5d8411b9251c0c94.png

    image.png.4d801db4cebc919e0a53f7d604472ac8.png


    I'm not sure where to set the Framework search path... Maybe that is the problem.

    image.png


  4. I'm using Dave Nottage's Kastri library and it is pretty great. I'm running into an issue, though, with the barcode feature and I'm not sure what's wrong.

     

    I use a TCameraComponent to capture the user's selfie when they sign in with their employee ID number.

     

    The code to create the camera is this:

     

          if not assigned (faceCamera) then
            begin
              faceCamera := TCameraComponent.Create (nil);
              faceCamera.Kind := FMX.Media.TCameraKind.FrontCamera;

              faceCamera.FocusMode := TFocusMode.ContinuousAutoFocus;
              faceCamera.OnSampleBufferReady := faceCameraSampleBufferReady;

            end;

     

    I'm not having any problem with the "selfie" camera.

     

    The barcode capability is only available in user interface after the user logs in. So, since my app has either the front or back camera on at any one time, my thinking is to use the same cameraComponent for the barcode scanning.

     

    First question I have: should I instantiate a second TCameraComponent for the back camera? Or can I share the component for both functions?

     

    I have another variable, barcodeCamera, but I don't instantiate a new object... I just point to faceCamera, like this:

     

    procedure TfrmMain.StartBarcodeCamera;
    begin
      barcode := '';  // the scan capability might find multiple barcodes, but only one will be returned in our code

     

      barcodeCamera := faceCamera; // 12/20/22 - share the camera component

     

      if barcodeCamera.Kind <> FMX.Media.TCameraKind.BackCamera then
        begin
          barcodeCamera.Kind := FMX.Media.TCameraKind.BackCamera;
          barcodeCamera.OnSampleBufferReady := barcodeCameraSampleBufferReady;
        end;

     

      FIsScanning := True;
     

      // i have a call to log.d to output to android log here, something like log.d ('StartBarcodeCamera - before barcodeCamera.Active := True');
      barcodeCamera.Active := True;
    end;

    I think I have a problem with google vision library not loading properly, so my 2nd question is, what does the following tell you, if anything, about my problem:

     

    What's happening is that the camera doesn't show... the barcodeCameraSampleBufferReady fires, and I get a few lines in DeviceLens that might shed some light:

     

    FMX: JCM Material: StartBarcodeCamera - before barcodeCamera.Active := True
    type=1400 audit(0.0:77655): avc: denied { read } for name="u:object_r:vendor_camera_prop:s0" dev="tmpfs" ino=4472 scontext=u:r:untrusted_app:s0:c117,c256,c512,c768 tcontext=u:object_r:vendor_camera_prop:s0 tclass=file permissive=0
    Access denied finding property "vendor.camera.hal1.packagelist"
    send ACTION_CAMERA_DEVICE_STARTED
    FMX: JCM Material: barcodeCameraSampleBufferReady
    FMX: JCM Material: barcodeCameraSampleBufferReady - setting FProcessTime := Now
    FMX: JCM Material: barcodeCameraSampleBufferReady - before FReader.Scan(FSectionBitmap)
    Local module descriptor class for com.google.android.gms.vision.dynamite.barcode not found.
    Considering local module com.google.android.gms.vision.dynamite.barcode:0 and remote module com.google.android.gms.vision.dynamite.barcode:0
    Cannot load feature, fall back to load whole module.
    Local module descriptor class for com.google.android.gms.vision.dynamite not found.
    Unsupported class loader
    Skipping duplicate class check due to unsupported classloader
    Considering local module com.google.android.gms.vision.dynamite:0 and remote module com.google.android.gms.vision.dynamite:2703
    Selected remote version of com.google.android.gms.vision.dynamite, version >= 2703
    Dynamite loader version >= 2, using loadModule2NoCrashUtils
    ClassLoader referenced unknown path:
    Unsupported class loader
    Verification of ix ix.d(android.content.Context, ir, java.lang.String) took 106.493ms
    Wrote stack traces to '[tombstoned]'
    Accessing hidden field Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; (light greylist, reflection)
    Considering local module com.google.android.gms.vision.barcode:0 and remote module com.google.android.gms.vision.barcode:224404100
    Selected remote version of com.google.android.gms.vision.barcode, version >= 224404100
     


  5. What's the best way to install a shortcut on android home screen when I install my app? If it matters I'm not using the play store. I'm using Delphi 11.1.

     

    I found some code (that was pretty old) but it is not working. My slight modifications of it is below:

     

    procedure addShortcut (const AppID : string);
    var
      ShortcutIntent: JIntent;
      addIntent: JIntent;
      wIconIdentifier : integer;
      wIconResource : JIntent_ShortcutIconResource;
    begin
      ShortcutIntent := TJIntent.JavaClass.init(SharedActivityContext, SharedActivityContext.getClass);
      ShortcutIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);

      addIntent := TJIntent.Create;
      addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_INTENT, TJParcelable.Wrap((shortcutIntent as ILocalObject).GetObjectID));
        // here we need to cast the intent as it's not done in delphi by default, not like java
      addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_NAME, StringToJString(Application.Title));
      addIntent.setAction(StringToJString('com.android.launcher.action.INSTALL_SHORTCUT'));

    //'com.embarcadero.HeaderFooterApplication'
      // get icon resource identifier
      wIconIdentifier := SharedActivity.getResources.getIdentifier(StringToJString('ic_launcher'),
          StringToJString('drawable'),
          StringToJString (AppID)); // if the app name change, you must change the package name
      wIconResource := TJIntent_ShortcutIconResource.JavaClass.fromContext(SharedActivityContext, wIconIdentifier);

      // set icon for shortcut
      addIntent.putExtra(TJIntent.JavaClass.EXTRA_SHORTCUT_ICON_RESOURCE, TJParcelable.Wrap((wIconResource as ILocalObject).GetObjectID));

      SharedActivityContext.sendBroadcast(addIntent);
    end;
     


  6. Not sure if there is a good way to compare list of jar files between two apps, but here is the top of list for both the working app and the non-working app. I did the "revert system files" click on both of these, several times on the one that is not working. I hate to do it, but at this point I think I need to start chopping out functionality until I get the non-working app to work again, and then work forward until I find what is causing the problem. In term of function, the one that is not working allows submission of photos to our server, so it wants to access gallery... the other working app does not try to access the gallery, so that is where I will start. I will report back with questions and progress. Thanks very much.

     

    Working app:

    image.png.d9df96e7c05993722a0f0997272e3bc6.png

     

    NON-working app:

    image.png.371897a0583544f5e9d8cbe297303990.png

     

     

     

    image.png


  7. The app is not giving me the error message anymore. When I launch it, I see splash screen, and then message "<MyAppName> has stopped, App info, close app".

     

    I added a log.d call in the project file before Application.Initialize; That log call does not show up in android log file.

     

    Here is the full android log. I bolded a line that seems really odd to meq:

     

    12-06 15:50:15.015    I    com.zunna.JCMPhotos    29570    29570    zunna.JCMPhoto    Late-enabling -Xcheck:jni
    12-06 15:50:15.249    E    com.zunna.JCMPhotos    29570    29570    libc    Access denied finding property "persist.vendor.sys.activitylog"
    12-06 15:50:18.107    D    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    Shutting down VM
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    FATAL EXCEPTION: main
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    Process: com.zunna.JCMPhotos, PID: 29570
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/base.apk"],nativeLibraryDirectories=[/data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/lib/arm, /data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/base.apk!/lib/armeabi-v7a, /system/lib]]
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.installProvider(ActivityThread.java:6427)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.installContentProviders(ActivityThread.java:5969)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5884)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.access$1200(ActivityThread.java:206)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1678)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.os.Handler.dispatchMessage(Handler.java:106)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.os.Looper.loop(Looper.java:193)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.main(ActivityThread.java:6702)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at java.lang.reflect.Method.invoke(Native Method)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/base.apk"],nativeLibraryDirectories=[/data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/lib/arm, /data/app/com.zunna.JCMPhotos-YQiq9zZupR4iE_EdtFvljA==/base.apk!/lib/armeabi-v7a, /system/lib]]
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.AppComponentFactory.instantiateProvider(AppComponentFactory.java:121)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    at android.app.ActivityThread.installProvider(ActivityThread.java:6411)
    12-06 15:50:18.117    E    com.zunna.JCMPhotos    29570    29570    AndroidRuntime    ... 10 more


  8. Really glad to have your feedback. I had already tried that and it did not help. Here is a bit of an odd thing I don't understand yet... I have 2 apps that use a lot of the same code, identical manifests and associated xml files. One works and one doesn't. I compared the deployment lists and they seem identical. The Armor X3 is a 32-bit device, so I'm running release version of 32-bit app. Here is the start of the android log for the WORKING app (non-working app log is above). I can send more of either log if that would help identify what is different. In the working app log, there is no mention of "fileprovider", but the same entries are in manifest.

     

    12-06 15:23:09.444    I    com.zunna.JCMTime    26899    26899    m.zunna.JCMTim    Late-enabling -Xcheck:jni
    12-06 15:23:09.593    W    com.zunna.JCMTime    26899    26899    re-initialized>    type=1400 audit(0.0:5735): avc: denied { read } for name="u:object_r:mtk_amslog_prop:s0" dev="tmpfs" ino=3397 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:mtk_amslog_prop:s0 tclass=file permissive=0
    12-06 15:23:09.598    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "persist.vendor.sys.activitylog"
    12-06 15:23:12.404    D    com.zunna.JCMTime    26899    26899    OpenGLRenderer    Skia GL Pipeline
    12-06 15:23:12.406    I    com.zunna.JCMTime    26899    26899    SurfaceFactory    [static] sSurfaceFactory = com.mediatek.view.impl.SurfaceFactoryImpl@9eeb266
    12-06 15:23:12.695    E    com.zunna.JCMTime    26899    26899        appName=com.zunna.JCMTime, acAppName=/system/bin/surfaceflinger
    12-06 15:23:12.696    E    com.zunna.JCMTime    26899    26899        0
    12-06 15:23:12.700    I    com.zunna.JCMTime    26899    26899    ConfigStore    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    12-06 15:23:12.701    I    com.zunna.JCMTime    26899    26899    ConfigStore    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
    12-06 15:23:12.703    I    com.zunna.JCMTime    26899    26899    BufferQueue    [unnamed-26899-0](this:0x8f58e000,id:0,api:0,p:-1,c:-1) BufferQueue core=(26899:com.zunna.JCMTime)
    12-06 15:23:12.706    W    com.zunna.JCMTime    26899    26899    m.zunna.JCMTime    type=1400 audit(0.0:5736): avc: denied { read } for name="u:object_r:graphics_debug_prop:s0" dev="tmpfs" ino=3373 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:graphics_debug_prop:s0 tclass=file permissive=0
    12-06 15:23:12.713    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "vendor.debug.sf.stc_interval"
    12-06 15:23:12.714    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "vendor.debug.bq.dump"
    12-06 15:23:12.710    W    com.zunna.JCMTime    26899    26899    m.zunna.JCMTime    type=1400 audit(0.0:5737): avc: denied { read } for name="u:object_r:debug_bq_dump_prop:s0" dev="tmpfs" ino=3334 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:debug_bq_dump_prop:s0 tclass=file permissive=0
    12-06 15:23:12.723    I    com.zunna.JCMTime    26899    26899    BufferQueueConsumer    [unnamed-26899-0](this:0x8f58e000,id:0,api:0,p:-1,c:26899) connect(C): consumer=(26899:com.zunna.JCMTime) controlledByApp=true
    12-06 15:23:12.724    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "vendor.debug.bq.dump"
    12-06 15:23:12.720    W    com.zunna.JCMTime    26899    26899    m.zunna.JCMTime    type=1400 audit(0.0:5738): avc: denied { read } for name="u:object_r:debug_bq_dump_prop:s0" dev="tmpfs" ino=3334 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:debug_bq_dump_prop:s0 tclass=file permissive=0
    12-06 15:23:12.724    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "vendor.debug.bq.line"
    12-06 15:23:12.720    W    com.zunna.JCMTime    26899    26899    m.zunna.JCMTime    type=1400 audit(0.0:5739): avc: denied { read } for name="u:object_r:graphics_debug_prop:s0" dev="tmpfs" ino=3373 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:graphics_debug_prop:s0 tclass=file permissive=0
    12-06 15:23:12.724    E    com.zunna.JCMTime    26899    26899    libc    Access denied finding property "vendor.debug.bq.dump"
    12-06 15:23:12.720    W    com.zunna.JCMTime    26899    26899    m.zunna.JCMTime    type=1400 audit(0.0:5740): avc: denied { read } for name="u:object_r:debug_bq_dump_prop:s0" dev="tmpfs" ino=3334 scontext=u:r:untrusted_app:s0:c106,c256,c512,c768 tcontext=u:object_r:debug_bq_dump_prop:s0 tclass=file permissive=0
    
    

  9. Related to tog message, java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider"

     

    Here is entry in androidmanifest.xml:

            <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="com.zunna.JCMPhotos.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths" />
            </provider>

     

    and here is the provider_paths.xml file:

     

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <files-path name="internal_private_files" path="." />
        <cache-path name="internal_cache_files" path="." />
        <external-path name="external_public_files" path="." />
        <external-files-path name="external_private_files" path="." />
        <external-cache-path name="external_cache_files" path="." />
        <external-media-path name="external_media_files" path="." />
    </paths>
     

    Do those entries make sense?


  10. I had been testing my app on a samsung tablet and a ulefone Armor X9 and had it all working, i thought. Now I'm trying to deploy to some other ulefone models (armor x3 and x5) and I'm able to install, but when i launch the app i get error "Application does not support this device" or the app immediately closes. Any thoughts on how to fix? Using deviceLens here is some of the logging

     

    12-05 16:52:39.495    I    com.zunna.JCMPhotos    20787    20787    zunna.JCMPhoto    Late-enabling -Xcheck:jni
    12-05 16:52:39.592    W    com.zunna.JCMPhotos    20787    20787    re-initialized>    type=1400 audit(0.0:1727): avc: denied { read } for name="u:object_r:mtk_amslog_prop:s0" dev="tmpfs" ino=3397 scontext=u:r:untrusted_app:s0:c109,c256,c512,c768 tcontext=u:object_r:mtk_amslog_prop:s0 tclass=file permissive=0
    12-05 16:52:39.596    E    com.zunna.JCMPhotos    20787    20787    libc    Access denied finding property "persist.vendor.sys.activitylog"
    12-05 16:52:40.054    D    com.zunna.JCMPhotos    20787    20787    AndroidRuntime    Shutting down VM
    12-05 16:52:40.064    E    com.zunna.JCMPhotos    20787    20787    AndroidRuntime    FATAL EXCEPTION: main
    12-05 16:52:40.064    E    com.zunna.JCMPhotos    20787    20787    AndroidRuntime    Process: com.zunna.JCMPhotos, PID: 20787
    12-05 16:52:40.064    E    com.zunna.JCMPhotos    20787    20787    AndroidRuntime    java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn't find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/com.zunna.JCMPhotos-pBkN5adkbbYEbIb8Jtd9VQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.zunna.JCMPhotos-pBkN5adkbbYEbIb8Jtd9VQ==/lib/arm, /data/app/com.zunna.JCMPhotos-pBkN5adkbbYEbIb8Jtd9VQ==/base.apk!/lib/armeabi-v7a, /system/lib]]
    12-05 16:52:40.064    E    com.zunna.JCMPhotos    20787    20787    AndroidRuntime    at android.app.ActivityThread.installProvider(ActivityThread.java:6427)
     


  11. I needed to get something working, so I wrote the code below. I want to use FireDac for database access, but I want to pass entire datasets to the datasnap client, and the only way I know how to do that now is to put the data in a TClientdataset and then send to client using CDS.Data.

     

    If I could use DBExpress to access the server database it is FAR simpler to pass datasets.

     

    If you feel like looking at code (working code, although not sure how efficient), please read below and tell me if there is a better way to do what I'm trying to do. Thank you.

     

    cdsFD : TClientDataset; // created with data module create

     

        procedure linkCDS;  // sub-procedure
        var
          i : integer;
          s, s2, s3 : string;
        begin
          if cdsFD.Active then cdsFD.Close;
          cdsFD.FieldDefs.Clear;
          cdsFD.FieldDefs.Assign(spFD.FieldDefs); // spFD is the TFDStoredProc with data from server that needs to be sent to client

     

          // field definitions from the server might have auto-increment fields, readonly fields and required fields... Turn all those off in the CDS

          for i := 0 to cdsFD.FieldDefs.Count - 1 do
            begin
              if cdsFD.FieldDefs .DataType = ftAutoinc then
                cdsFD.FieldDefs .DataType := ftInteger;

     

              if DB.faReadonly in cdsFD.FieldDefs .Attributes then
                cdsFD.FieldDefs .Attributes := cdsFD.FieldDefs .Attributes - [DB.faReadonly];

     

              if DB.faRequired in cdsFD.FieldDefs .Attributes then
                cdsFD.FieldDefs .Attributes := cdsFD.FieldDefs .Attributes - [DB.faRequired];

            end;


          cdsFD.CreateDataSet; 
          cdsFD.Active := true;

     

          spFD.First;
          while not spFD.EOF do
            begin
              cdsFD.Insert;
              cdsFD.copyFields (spFD);
              cdsFD.Post;

              spFD.Next;
            end;
        end;

     

    // start of main procedure

    begin
      GetFDConnection;  // create new TFDConnection named DBCFD

      spFD.Connection := DBCFD;

     

      spFD.StoredProcName := 'JCMGetAllTimeLookupLists';
      spFD.Prepare;
      spFD.paramByName ('@TSLastRequest').Value := lastRequestTimeStamp;
      spFD.paramByName ('@ReturnTS').Value := 'N';

      spFD.open;  // retrieves 19 datasets

     

      Result := VarArrayCreate ([0, 19], varVariant);

     

      linkCDS;  // see above... put FDStoredProc data into a CDS

     

      result [0] := cdsFD.Data;

      for i := 1 to 18 do
        begin
          spFD.NextRecordSet;

     

          linkCDS;

          result  := cdsFD.Data;  // weird... I keep trying to make this result [ i ] :=, but when I hit save (on delphipraxis), the [ i ] keeps disappearing
        end;

     

      spFD.Close;
    end;


  12. My server needs to send 19 datasets to the android client (datasnap). I nearly have things working using Firedac, but I cannot figure out how to make a Clientdataset use datasets in the TFDStoredProc other than the 1st dataset.

     

    I have a SQL (Microsoft) stored procedure, 'JCMGetAllLookupLists' that returns 19 datasets. The TFDStoredProc (spFD) can step through those datasets easily enough using spFD.NextRecordset, but I don't know how to get the dataset in the CDS so I can send CDS.Data back to the cliente.

     

    here is the gyst of my code. The code below is in a server function that returns an OleVariant

     

        Result := VarArrayCreate ([0, 19], varVariant);  // result [19] is not a dataset

     

        spFD.StoredProcName := 'JCMGetAllLookupLists';
        spFD.Prepare;
        spFD.paramByName ('@TSLastRequest').Value := lastRequestTimeStamp;
        spFD.paramByName ('@ReturnTS').Value := 'N';

        cdsFD.Open;  // cdsFD is linked to a datasetprovider (dspFD) using cdsFD.Providername, and dspFD.Dataset is set to spFD

     

        // at this point, cdsFD can access the first dataset in spFD

        // but, how to get to the other 18 datasets?


        result [0] := cdsFD.Data;  // this works fine

     

        // the loop below does not work... cdsFD.Data always has the data from spFD's FIRST dataset...

        for i := 1 to 18 do
          begin
            spFD.NextRecordSet;
            result := cdsFD.Data;
          end;
     

    I could make 19 different calls to the SQL server to get the 19 datasets (that's what I'm doing now), but it seems much more efficient if the server returns all 19 datasets at once and then my server code pulls out the data for each to send back to the client.

     

    Does anyone know how to step through FD datasets using NextRecordset in a way that a linked ClientDataset "sees" each of the FD datasets?


  13. I've only ever used TClientDataset with TSQLQuery, with the needed TDatasetProvider in between (TSQLQuery -> TDatasetProvider -> TClientDataset).

     

    I have a project to update an old datasnap server that used DBExpress (TSQLQuery comes from there). I'm wondering if I can drop DBExpress and use FireDac, which I know much better.

     

    Does this component linking work or make sense: (TFDStoredProc -> TDatasetProvider -> TClientDataset)?

     

    Or better, is there a way to pass an entire dataset using datasnap, but using FD datasets, not DBExpress datasets? With DBX, you use TClientDatasets (CDS) to pass an entire table of data with metadata with these lines:

     

    transData := CDS.Data; // on the client side, then a server call passes the transData (array of OleVariants) to a server procedure. CDS is linked to a local SQLite table

     

    CDS.Data := transData ; // on the server side, and now the TClientDataset has an entire table.

     

    The big picture is to have an efficient way for a client (android datasnap client) to send tables of data to the server, and for the server to efficiently save that data as new rows in existing SQL Server tables. I mention that because I feel there is probably a good way to take CDS.Data (or its FD equivalent) and save all rows to a server table without writing much code, but I wouldn't know where to start my research to do that.

     

    Discussion and feedback are really apprecaited.

     

    Keith

     


  14. I tested a simple case and have found that even in very simple example (3 integer fields), I get the "invalid parameter" error. So the problem or concern I have about the ftTimestamp versus ftDatetime may or may not be relevant.

     

    Here is my test code:

     

        procedure testCDS;
        var
          i : integer;
          s : string;
        begin
          resetCDS (CDSSv);  // the reset calls clear fields and parameters from the clientdataset and query
          resetQ (QSv);

     

          s := 'select fld1, fld2, fld3 from testTbl where 1=0';  // I have other code that builds this select statement, but allowing the select from database to build the dataset fields in memory has many advantages (works with multiple tables, for exampe)

          QSv.SQL.Add (s);
          CDSSv.Open; // open empty dataset, all fields should be available now

     

          // attempt to add 3 rows to the table (brand new table, no indexes, just for testing)

          for i := 1 to 3 do
            begin
              CDSSv.Insert;
              CDSSv.fields [0].Value := i;
              CDSSv.fields [1].Value := i;
              CDSSv.fields [2].Value := i;
              CDSSv.Post;  // no error yet... rows are successfully added to the CDS
            end;

     

          try
            CDSSv.ApplyUpdates (-1);    // This is the statement that throws the invalid parameter exception...
          except on e:exception do
            begin
    {$IFDEF DBUG} DMServerContainer.writeDbugS ('testCDS - exception - ' + e.Message);  {$ENDIF}
            end;
          end;
        end;


    Also... if i go a different route and build an SQL Insert statement and then execute it, the rows are saved to the SQL database as expected... IOW, the code below works, so there is something broken with TSQLQuery -> TDatasetProvider -> TClientDataset

     

    s := 'insert testTbl (fld1, fld2, fld3) values (1, 1, 1), (2, 2, 2), (3, 3, 3)';

    QSv.SQL.Add (s);

    QSv.ExecSQL;

     

    So... I can rewrite my code, but then I need to handle strings, datetimes and blob/photo fields which is more work or not possible with an SQL statement (how to insert a photo into image field using an insert statement?).


  15. The exception reported by CDS.applyUpdates is "Invalid parameter."

     

    I do not think the datasnap part of this is relevant... maybe I should not have mentioned that at all, but was trying to be complete.

     

    With a TSQLQuery (named QSv), if I run a select statement like select fld1, fld2 from tbl where 1=0, and fld2 is a datetime field in SQL Server, the QSv.fields [1].datatype is not ftDatetime, it is ftTimestamp (16 bits long), and I think that is the source of the failure when applyUpdates tries to add rows back to the database table.


  16. One more thing... I've read that for certain field types, you will get the "invalid parameter" error, particularly with strings and GUID if datasize is not specified...

     

    Here's something I'm seeing that might be the problem, but I don't know how to fix.

     

    After CDSSv.open (which opens the blank dataset on the server), I loop through all fields to see that fieldtype, datasize, etc are...

     

    I have several fields in the underlying SQL table defined as datetime fields (8 bytes).

     

    In Delphi, after cdsSv.open, these fields show datatype as ftTimeStamp and datasize as 16 (not ftDateTime and size 8). Why would that happen? And how to fix?

     

    To summarize:

     

    My SQL is like this: select RegID, myDate from table;

    myDate in the sQL table is datetime

    After I open the dataset, the field type of myDate is ftTimestamp, not ftDatetime. That seems like it might cause the invalid parameter error when I apply updates.

     

    Thanks for looking through all this.


  17. I added some debugging output and have determined a few things:

     

    After CDSSv.open... CDSSv.CanModify is TRUE, cdsSv.ReadOnly is FALSE

     

    And I loop through all fields in CDSSv and each field also has CanModify = TRUE and ReadOnly = FALSE

     

    So I don't think it is a problem that the dataset or any field is read only.

     

    I have searched for why TClientDataSet.ApplyUpdates might generate and exception "Invalid Parameter" but I haven't found anything.


  18. Delphi 11 using DataSnap, although the communication between client and server seems fine, so datasnap I don't think is relevant. Problem is with DBExpress and readonly dataset, I think.

     

    I don't know a short way to ask for help on this, but here goes:

     

    On my datasnap server I'm using TSQLConnection to access SQL Server. I use TSQLQuery to run a query that gets an empty dataset from the SQL Server. The TSQLQuery is connected to a dataset provider which in turn is connected to a TClientDataset. here is some of my code... this code is called after to datasnap client calls the server method to add 1 or more rows to tables on the server:

     

        function copyDataToServer (tblName   : string;
                                   dataIndex : integer) : integer;
        var
          i : integer;
          s : string;
          s2 : string;
        begin
          result := 0;

     

          // tmpCDS is a TClientDataset that has the data to be added to the server... the client passes a clientDataset.Data to the server using a Variant array.

          tmpCDS.Data := transData [dataIndex];

     

          //  build a query to pull empty dataset from server

              s := '';

              for i := 0 to tmpCDS.FieldCount - 1 do
                if s = '' then
                  s := tmpCDS.Fields .FieldName
                else
                  s := s + ', ' + tmpCDS.Fields .FieldName;

              s := 'select ' + s + ' from ' + tblName + 'Transfer where RegID = ' + intToStr (RegID);

     

              // QSv is a TSQLQuery

              QSv.SQL.Add (s);  
              QSv.Prepared := true;

     

               // CDSSv is the TClientDataset connected to datasetprovider, which in turn is connected to QSv

              CDSSv.Open;  // this successfully gets an empty dataset for the table in question - after the open, CDSSv.CanModify is true, Readonly is false, recordCount is 0... all as they should be.

     

              tmpCDS.First;  // this is the dataset from the datasnap client

              while not tmpCDS.EOF do
                begin             

                  CDSSv.Insert;

     

                  // not all fields might be present, and order of fields might change...

                  for i := 0 to tmpCDS.FieldCount - 1 do
                     CDSSv.FieldByName (tmpCDS.Fields .FieldName).Value := tmpCDS.Fields .Value;

     

                  CDSSv.Post;  // this works, new row is saved in the clientdataset

     

                  tmpCDS.Next;
                end;

     

               // at this point 100 +/- rows are in the clientdataset, CDSSv

              try
                result := CDSSv.ApplyUpdates (-1);    // save recs to the transfer table - THIS BLOWS UP!!!
              except on e:exception do
                begin
                  writeDbugS ('result := CDSSave.ApplyUpdates (-1) exception - ' + e.Message;); // exception message is Invalid parameter
                end;
              end;
     

    Any help is much appreciated... The above code has worked for 5 years. I'm updating things to try to keep up with android versions (for the client side of the datasnap) and in the process needed to update the datasnap server, but I've done something to make the above code stop working and I havn't been able to track it down.

     


  19. Thank you for the link.

     

    Re: when permissions are requested, it's not that I think I need to request outside the main thread, but the logic makes more sense to me to request the permission within the task that downloads the file.

     

    IE, within the task, request permission to save to external storage, then if not granted, save the downloaded file to private storage

     

    rather than:

     

    request permission to save to external storage

    start task to download a file.

     

    Do you think it's a problem to request permissions outside the main ui?

×