LAMW - (SOLVED) simple esc/POS printing bridge? lazarus / 43-Android ---------------------------------------------------------------------- Mongkey · 2023-05-28 00:46 Library: https://github.com/DantSu/ESCPOS-ThermalPrinter-Android 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 EscPosPrinter printer = new EscPosPrinter(BluetoothPrintersConnections.selectFirstPaired(), 203, 48f, 32);printer    .printFormattedText(        "[C]" + PrinterTextParserImg.bitmapToHexadecimalString(printer, this.getApplic ationContext().getResources().getDrawableForDensity(R.drawable.logo, DisplayMetrics.DENSITY_MEDIUM))+"\n" +        "[L]\n" +        "[C]ORDER N°045\n" +        "[L]\n" +      "[C]================================\n" +        "[L]\n" +      "[L]BEAUTIFUL SHIRT[R]9.99e\n" +        "[L]  + Size : S\n" +      "[L]\n" +        "[L]AWESOME HAT[R]24.99e\n" +        "[L]  + Size : 57/58\n" +        "[L]\n" +        "[C]--------------------------------\n" +        "[R]TOTAL PRICE :[R]34.98e\n" +        "[R]TAX :[R]4.23e\n" +        "[L]\n" +        "[C]================================\n" +        "[L]\n" +        "[L]Customer :\n" +        "[L]Raymond DUPONT\n" +        "[L]5 rue des girafes\n" +        "[L]31547 PERPETES\n" +        "[L]Tel : +33801201456\n" +        "[L]\n" +      "[C]831254784551\n" +      "[C]https://dantsu.com/"    );  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 package com.dantsu.thermalprinter; import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat; import android.Manifest;import android.annotation.SuppressLint;import android.app.AlertDialog;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.pm.PackageManager;import android.hardware.usb.UsbDevice;import android.hardware.usb.UsbManager;import android.os.Bundle;import android.util.DisplayMetrics;import android.util.Log;import android.widget.Button;import android.widget.EditText; import com.dantsu.escposprinter.connection.DeviceConnection;import com.dantsu .escposprinter.connection.bluetooth.BluetoothConnection;import com.dan tsu.escposprinter.connection.bluetooth.BluetoothPrintersConnections;im port com.dantsu.escposprinter.connection.tcp.TcpConnection;import com.dantsu.escposprinter.connection.usb.UsbConnection;import com.dantsu.escposprinter.connection.usb.UsbPrintersConnections;import com.dantsu.escposprinter.textparser.PrinterTextParserImg;import com.dantsu.thermalprinter.async.AsyncBluetoothEscPosPrint;import com.dantsu.thermalprinter.async.AsyncEscPosPrint;import com.dantsu.thermalprinter.async.AsyncEscPosPrinter;import com.dantsu.thermalprinter.async.AsyncTcpEscPosPrint;import com.dantsu.thermalprinter.async.AsyncUsbEscPosPrint; import java.text.SimpleDateFormat;import java.util.Date; public class MainActivity extends AppCompatActivity {      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button button = (Button) this.findViewById(R.id.button_bluetooth_browse);        button.setOnClickListener(view -> browseBluetoothDevice());        button = (Button) findViewById(R.id.button_bluetooth);        button.setOnClickListener(view -> printBluetooth());        button = (Button) this.findViewById(R.id.button_usb);        button.setOnClickListener(view -> printUsb());        button = (Button) this.findViewById(R.id.button_tcp);        button.setOnClickListener(view -> printTcp());     }      /*========== ====================================================================== ==============    ======================================BLUETOOTH PART============================================    ================== ====================================================================== ======*/     public interface OnBluetoothPermissionsGranted {        void onPermissionsGranted();    }     public static final int PERMISSION_BLUETOOTH = 1;    public static final int PERMISSION_BLUETOOTH_ADMIN = 2;    public static final int PERMISSION_BLUETOOTH_CONNECT = 3;    public static final int PERMISSION_BLUETOOTH_SCAN = 4;     public OnBluetoothPermissionsGranted onBluetoothPermissionsGranted;     @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {            switch (requestCode) {                case MainActivity.PERMISSION_BLUETOOTH:                case MainActivity.PERMISSION_BLUETOOTH_ADMIN:                case MainActivity.PERMISSION_BLUETOOTH_CONNECT:                case MainActivity.PERMISSION_BLUETOOTH_SCAN:                    this.checkBluetoothPermissions(this.onBluetoothPermissionsGranted);                  break;            }        }    }     public void checkBluetoothPermissions(OnBluetoothPermissionsGranted onBluetoothPermissionsGranted) {        this.onBluetoothPermissionsGranted = onBluetoothPermissionsGranted;      if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH}, MainActivity.PERMISSION_BLUETOOTH);        } else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_ADMIN}, MainActivity.PERMISSION_BLUETOOTH_ADMIN);        } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, MainActivity.PERMISSION_BLUETOOTH_CONNECT);        } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN}, MainActivity.PERMISSION_BLUETOOTH_SCAN);        } else {            this.onBluetoothPermissionsGranted.onPermissionsGranted();        }  }     private BluetoothConnection selectedDevice;     public void browseBluetoothDevice() {        this.checkBluetoothPermissions(() -> {            final BluetoothConnection[] bluetoothDevicesList = (new BluetoothPrintersConnections()).getList();             if (bluetoothDevicesList != null) {                final String[] items = new String[bluetoothDevicesList.length + 1];                items[0] = "Default printer";                int i = 0;                for (BluetoothConnection device : bluetoothDevicesList) {                  items[++i] = device.getDevice().getName();                }               AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this);                alertDialog.setTitle("Bluetooth printer selection");                alertDialog.setItems(                    items,                    (dialogInterface, i1) -> {                        int index = i1 - 1;                        if (index == -1) {                            selectedDevice = null;                        } else {                          selectedDevice = bluetoothDevicesList[index];                      }                        Button button = (Button) findViewById(R.id.button_bluetooth_browse);                        button.setText(items[i1]);                    }                );               AlertDialog alert = alertDialog.create();                alert.setCanceledOnTouchOutside(false);                alert.show();          }        });     }     public void printBluetooth() {        this.checkBluetoothPermissions(() -> {            new AsyncBluetoothEscPosPrint(                this,                new AsyncEscPosPrint.OnPrintFinished() {                    @Override                  public void onError(AsyncEscPosPrinter asyncEscPosPrinter, int codeException) {                        Log.e("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : An error occurred !");                    }                     @Override                    public void onSuccess(AsyncEscPosPrinter asyncEscPosPrinter) {                        Log.i("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : Print is finished !");                    }                }          )                .execute(this.getAsyncEscPosPrinter(selectedDevice));        });    }     /*============================================================== ================================    ===========================================USB PART=============================================    ================= ====================================================================== =======*/     private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {        public void onReceive(Context context, Intent intent) {            String action = intent.getAction();            if (MainActivity.ACTION_USB_PERMISSION.equals(action)) {                synchronized (this) {                    UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);                  UsbDevice usbDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);                  if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {                        if (usbManager != null && usbDevice != null) {                            new AsyncUsbEscPosPrint(                              context,                                new AsyncEscPosPrint.OnPrintFinished() {                                  @Override                                    public void onError(AsyncEscPosPrinter asyncEscPosPrinter, int codeException) {                                      Log.e("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : An error occurred !");                                  }                                     @Override                                    public void onSuccess(AsyncEscPosPrinter asyncEscPosPrinter) {                                      Log.i("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : Print is finished !");                                  }                                }                          )                                .execute(getAsyncEscPosPrinter(new UsbConnection(usbManager, usbDevice)));                        }                    }              }            }        }    };     public void printUsb() {        UsbConnection usbConnection = UsbPrintersConnections.selectFirstConnected(this);        UsbManager usbManager = (UsbManager) this.getSystemService(Context.USB_SERVICE);         if (usbConnection == null || usbManager == null) {            new AlertDialog.Builder(this)                .setTitle("USB Connection")              .setMessage("No USB printer found.")                .show();            return;        }         PendingIntent permissionIntent = PendingIntent.getBroadcast(            this,          0,            new Intent(MainActivity.ACTION_USB_PERMISSION),          android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S ? PendingIntent.FLAG_MUTABLE : 0      );        IntentFilter filter = new IntentFilter(MainActivity.ACTION_USB_PERMISSION);        registerReceiver(this.usbReceiver, filter);        usbManager.requestPermission(usbConnection.getDevice(), permissionIntent);    }     /*======================================== ======================================================    =========================================TCP PART===============================================    =============== ====================================================================== =========*/     public void printTcp() {        final EditText ipAddress = (EditText) this.findViewById(R.id.edittext_tcp_ip);      final EditText portAddress = (EditText) this.findViewById(R.id.edittext_tcp_port);         try {            new AsyncTcpEscPosPrint(                this,                new AsyncEscPosPrint.OnPrintFinished() {                    @Override                  public void onError(AsyncEscPosPrinter asyncEscPosPrinter, int codeException) {                        Log.e("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : An error occurred !");                    }                     @Override                    public void onSuccess(AsyncEscPosPrinter asyncEscPosPrinter) {                        Log.i("Async.OnPrintFinished", "AsyncEscPosPrint.OnPrintFinished : Print is finished !");                    }                }          )                .execute(                    this.getAsyncEscPosPrinter(                        new TcpConnection(                            ipAddress.getText().toString(),                          Integer.parseInt(portAddress.getText().toString())                      )                    )                );        } catch (NumberFormatException e) {            new AlertDialog.Builder(this)                .setTitle("Invalid TCP port address")                .setMessage("Port field must be an integer.")                .show();            e.printStackTrace();      }    }     /*====================================================== ========================================    ===================================ESC/POS PRINTER PART=========================================    ===================== ====================================================================== ===*/     /**     * Asynchronous printing     */    @SuppressLint("SimpleDateFormat")    public AsyncEscPosPrinter getAsyncEscPosPrinter(DeviceConnection printerConnection) {        SimpleDateFormat format = new SimpleDateFormat("'on' yyyy-MM-dd 'at' HH:mm:ss");        AsyncEscPosPrinter printer = new AsyncEscPosPrinter(printerConnection, 203, 48f, 32);        return printer.addTextToPrint(            "[C]" + PrinterTextParserImg.bitmapToHexadecimalString(printer, this.getApplic ationContext().getResources().getDrawableForDensity(R.drawable.logo, DisplayMetrics.DENSITY_MEDIUM)) + "\n" +                "[L]\n" +                "[C]ORDER N°045\n" +              "[L]\n" +                "[C]" + format.format(new Date()) + "\n" +                "[C]\n" +              "[C]================================\n" +                "[L]\n" +                "[L]BEAUTIFUL SHIRT[R]9.99€\n" +              "[L]  + Size : S\n" +                "[L]\n" +              "[L]AWESOME HAT[R]24.99€\n" +                "[L]  + Size : 57/58\n" +                "[L]\n" +                "[C]--------------------------------\n" +                "[R]TOTAL PRICE :[R]34.98€\n" +                "[R]TAX :[R]4.23€\n" +              "[L]\n" +                "[C]================================\n" +                "[L]\n" +                "[L]Customer :\n" +                "[L]Raymond DUPONT\n" +                "[L]5 rue des girafes\n" +              "[L]31547 PERPETES\n" +                "[L]Tel : +33801201456\n" +                "\n" +                "[C]831254784551\n" +                "[L]\n" +                "[C]https://dantsu.com/\n"        );    }} ---------------------------------------------------------------------- jmpessoa · 2023-05-28 18:40 Ok. I will try implement a "jEscPosPrinter"  LAMW component! Thank you! ---------------------------------------------------------------------- Mongkey · 2023-05-29 02:11 Thank you mr. JMP ---------------------------------------------------------------------- jmpessoa · 2023-05-31 23:51 Done! New "jsEscPosThermalPrinter"   component!  need: 1)AppCompat theme 2)gradle:  compileSdkVersion 33  targetSdkVersion 33 New demo "AppCompatEscPosThermalPrinterDemo1"  (please, test it!  I dont have a thermal printer....) ---------------------------------------------------------------------- Insid3Code · 2023-06-01 15:41 Hi, Tested... Thank you for this Nice work! ---------------------------------------------------------------------- jmpessoa · 2023-06-01 16:15 QuoteBethoven composed much of his wonderful work without listening anymore.... Doing a simple coding without having an instrument to test it, is possible for mere mortals....  Thank you! ---------------------------------------------------------------------- Mongkey · 2023-06-02 00:09 Thank you! Printing just like on kotlin ---------------------------------------------------------------------- Mongkey · 2023-06-02 01:56 Thank you, wishing you good health and happiness  Mr. JMP, My test result: It really slow, on every print just like on first print, seems getlist() printer first on all print, Could you add selectFirstPaired() not getlist() on printing? ---------------------------------------------------------------------- Mongkey · 2023-06-02 03:16 I got another method very fast on printing Mr. JMP, you just need add call procedure on jbluetoothclient, image, custom font already added. this attachment is the result ---------------------------------------------------------------------- jmpessoa · 2023-06-02 03:21 QuoteCould you add selectFirstPaired() not getlist() on printing? Yes, "selectFirstPaired()" is already the API used by  LAMW "InitConnection" for Bluetooth! QuoteI got another method very fast on printing Mr. JMP.... What another method? ---------------------------------------------------------------------- Mongkey · 2023-06-02 03:27 jBluetoothclientsocket.java you just need to make proper call procedure and improve, bridging from java to pas is hard for me  . More and more simple step by step java to pas bridging tutorial would be appreciated  Ability: custom font image unicode need improvement: adding barcode print ability would be nice. ---------------------------------------------------------------------- jmpessoa · 2023-06-02 06:27 Quoteyou just need to make proper call procedure and improve, bridging from java to pas is hard for me Ok. What functions from the new "jBluetoothclientsocket.java"  you need a bridge to be called from to Pascal/LAMW side? ---------------------------------------------------------------------- Mongkey · 2023-06-02 07:23 Hello Mr JMP, i already tried bridging, but still failed, how to solve? 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 void print_Custom(String _message, int _size, int _align) {        printCustom(_message, _size, _align); // total 32 char in a single line    }  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 print_Custom(var _message: string; _size:integer; _align:integer);  overload;  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 jBluetoothClientSocket.print_Custom(var _message: string; _size:integer; _align:integer);begin  //in designing component state: set value here...  if FInitialized then     jBluetoothClientSocket_print_Custom(gApp.jni.jEnv, FjObject, _message, _size, _align);end;   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 jBluetoothClientSocket_print_Custom(env: PJNIEnv; _jbluetoothclientsocket: JObject; var _message: string; _size: integer; _align: integer);var  jParams: array[0..0] of jValue;  jMethod: jMethodID=nil;  jCls: jClass=nil;begin  jParams[0].l:= env^.NewStringUTF(env, PChar(_message));  jCls:= env^.GetObjectClass(env, _jbluetoothclientsocket);  jMethod:= env^.GetMethodID(env, jCls, 'print_Custom', '(Ljava/lang/String;)V');  env^.CallVoidMethodA(env, _jbluetoothclientsocket, jMethod, @jParams);env^.DeleteLocalRef(env,jParams[0].l);  env^.DeleteLocalRef(env, jCls);end;  f_bluetooth.jBluetoothClientSocket1.print_Custom('test',3,1); this one still raising error: u_order.pas(2696,43) Error: identifier idents no member "print_Custom" Thank you. ---------------------------------------------------------------------- jmpessoa · 2023-06-02 08:50 ...................... ---------------------------------------------------------------------- jmpessoa · 2023-06-02 08:53 Using IDE menu "Tools" --> [LAMW ...] --->  "New jComponent Create"  :   (see picture) You got into the page/tab  "Pascal": 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 ujbluetoothclientsocket; {$mode delphi} interface uses  Classes, SysUtils, And_jni, AndroidWidget; type {warning: draft "jBluetoothClientSocket" complement....}{         copy/add to *jbluetoothclientsocket.pas" file} jBluetoothClientSocket = class public    procedure print_Custom(_message: string; _size: integer; _align: integer); end; procedure jBluetoothClientSocket_print_Custom(env: PJNIEnv; _jbluetoothclientsocket: JObject; _message: string; _size: integer; _align: integer);  implementation {---------  jBluetoothClientSocket  --------------} procedure jBluetoothClientSocket.print_Custom(_message: string; _size: integer; _align: integer);begin  //in designing component state: set value here...  if FInitialized then     jBluetoothClientSocket_print_Custom(gApp.jni.jEnv, FjObject, _message ,_size ,_align);end; {-------- jBluetoothClientSocket_JNI_Bridge ----------} procedure jBluetoothClientSocket_print_Custom(env: PJNIEnv; _jbluetoothclientsocket: JObject; _message: string; _size: integer; _align: integer);var  jParams: array[0..2] of jValue;  jMethod: jMethodID=nil;  jCls: jClass=nil;label  _exceptionOcurred;begin  if (env = nil) or (_jbluetoothclientsocket = nil) then exit;  jCls:= env^.GetObjectClass(env, _jbluetoothclientsocket);  if jCls = nil then goto _exceptionOcurred;  jMethod:= env^.GetMethodID(env, jCls, 'print_Custom', '(Ljava/lang/String;II)V');  if jMethod = nil then begin env^.DeleteLocalRef(env, jCls); goto _exceptionOcurred; end;   jParams[0].l:= env^.NewStringUTF(env, PChar(_message));  jParams[1].i:= _size;  jParams[2].i:= _align;   env^.CallVoidMethodA(env, _jbluetoothclientsocket, jMethod, @jParams);env^.DeleteLocalRef(env,jParams[0].l);   env^.DeleteLocalRef(env, jCls);  _exceptionOcurred: jni_ExceptionOccurred(env);end; end.  Now copy the generated code "by parts' to the  real  "bluetoothClientSocket.pas" in the folder "android_bridges".... after that do a "Run" --> "Clean up and Build"  on your LAMW project.... do fix the  "Error: identifier idents no member "print_Custom"" ---------------------------------------------------------------------- Mongkey · 2023-06-02 09:20 1 by 1, begin to understand, only print_Text, print_Line succeed  , 2 others still fail. just want to bring this 4: 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 print_line();  overload;    procedure print_Text(_message: string);  overload;    procedure print_Custom(_message: string; _size:integer; _align:integer);  overload;    procedure print_Photo(var _fullFilename: string);  overload;  Seems got the failed suspect  -> must be (Ljava/lang/String;II)  Thank you! ---------------------------------------------------------------------- jmpessoa · 2023-06-02 15:52 for "print_Custom": Quote'(Ljava/lang/String;II)V' But you don't need to code..... Use the code generator as shown in the picture! And yes, you can generate code for several methods at once ..... ref: https://github.com/jmpessoa/lazandroidmodulewizard/blob/master/docs/ho w_to_create_new_components.txt ---------------------------------------------------------------------- Mongkey · 2023-06-02 22:20 Thank you Mr. JMP, your tools are great!, Let me try first  , --> WORK like a pro, java to pas bridge programmer  I tried jar file as component, but it always give list out of bound index -> SOLVED  , i add if listbox1 empty it notifies the importer to re select java method.