Reputation: 812
I recently got my hands on a Android barcode scanner device. I want to write a small inventory multi-device app in Delphi 10 Seattle. Scanner has two mode settings to return scanned barcode, first mode just passes barcode to an focused edit control, second one is broadcast mode. Because Delphi still has some quirks with edit controls which are not working properly especially in tandem with virtual keyboard in android enviroment, I have to use broadcast mode. On the web I found manual with little to none helpful info, API to control device, and android demo application written in eclipse.
I was able to get API wrapper for Delphi and successfully control device, change parameters, turn on off scanner and etc.
Yet doe to poor understanding how android intent and broadcasting works,I am not able to successfully implement it.
I did study intent sample for Delphi http://docwiki.embarcadero.com/CodeExamples/Seattle/en/FMX.Android_Intents_Sample. Did run Android intent sample app and it did work.
Eclipse android demo project is working fine too, did compile and run it without a problem. Dilemma now is how to receive broadcasted intent in Delphi. I have manifest.xml and mainactivity code from working eclipse demo here...
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testscan"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.testscan.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Mainactivity:
package com.example.testscan;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.device.ScanDevice;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
public class MainActivity extends Activity {
ScanDevice sm;
private final static String SCAN_ACTION = "scan.rcv.message";
private String barcodeStr;
private EditText showScanResult;
private BroadcastReceiver mScanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
byte[] barocode = intent.getByteArrayExtra("barocode");
int barocodelen = intent.getIntExtra("length", 0);
byte temp = intent.getByteExtra("barcodeType", (byte) 0);
android.util.Log.i("debug", "----codetype--" + temp);
barcodeStr = new String(barocode, 0, barocodelen);
showScanResult.append("tere");
showScanResult.append(barcodeStr);
showScanResult.append("\n");
// showScanResult.setText(barcodeStr);
sm.stopScan();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sm = new ScanDevice();
CheckBox ch = (CheckBox) findViewById(R.id.checkBox1);
if(sm.getOutScanMode()==1){
ch.setChecked(true);
}else{
ch.setChecked(false);
}
ch.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
// TODO Auto-generated method stub
if(arg1){
sm.setOutScanMode(1);
}else{
sm.setOutScanMode(0);
}
}});
showScanResult=(EditText) findViewById(R.id.editText1);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.openScanner:
System.out.println("openScanner = "+sm.getOutScanMode());
sm.openScan();
break;
case R.id.closeScanner:
sm.closeScan();
break;
case R.id.startDecode:
sm.startScan();
break;
case R.id.stopDecode:
sm.stopScan();
break;
case R.id.start_continue:
sm.setScanLaserMode(4);
break;
case R.id.stop_continue:
sm.setScanLaserMode(8);
break;
case R.id.close:
finish();
break;
default:
break;
}
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if(sm != null) {
sm.stopScan();
}
unregisterReceiver(mScanReceiver);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(SCAN_ACTION);
registerReceiver(mScanReceiver, filter);
}
}
EDIT: 2017-04-24
I found a Japanese blogger who wrote an article about creating simple broadcaster receiver using Delphi 10 Seattle and newer versions http://www.gesource.jp/weblog/?p=7269 . Which, I later discovered, was mentioned in one of @alitrun mentioned sources comments. So, to work with scanner in broadcast mode you need U8000S_ScanSDK.pas jar wrapper to access and control device. it's needed to set scanner app in broadcastmode. Then you need to create BroadcastReceiverListener class ...
Simple port of android app mentioned above is here:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics,
FMX.Dialogs,
FMX.Controls.Presentation, FMX.Edit,
Androidapi.JNIBridge, Androidapi.JNI.Embarcadero,
Androidapi.JNI.GraphicsContentViewText,
U8000S_ScanSDK; { U8000S_ScanSDK.jar wrapper }
type
TMyReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
public
constructor Create;
procedure onReceive(context: JContext; intent: JIntent); cdecl;
end;
TForm1 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FMyListener: TMyReceiver;
FBroadcastReceiver: JFMXBroadcastReceiver;
ScanDevice: JScanDevice; { U8000S_ScanSDK.jar api device interface }
procedure managebarcodescan(barcode: string);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Androidapi.Helpers,
Androidapi.JNI.JavaTypes;
{$R *.fmx}
function HexToString(H: String): String;
var
I: Integer;
begin
Result := '';
for I := 1 to length(H) div 2 do
Result := Result + Char(StrToInt('$' + Copy(H, (I - 1) * 2 + 1, 2)));
end;
constructor TMyReceiver.Create;
begin
inherited;
end;
procedure TMyReceiver.onReceive(context: JContext; intent: JIntent);
var
barocode: tjavaarray<System.byte>;
len: Integer;
buffer: string;
I: Integer;
begin
if JStringToString(intent.getAction) = 'scan.rcv.message' then
begin
len := intent.getIntExtra(StringToJString('length'), 0);
barocode := intent.getByteArrayExtra(StringToJString('barocode'));
for I := 0 to len - 1 do
begin
buffer := buffer + inttohex(barocode[I], 2);
end;
buffer := HexToString(buffer);
barocode.Free;
// do something with result
Form1.managebarcodescan(buffer);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Filter: JIntentFilter;
begin
FMyListener := TMyReceiver.Create;
FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FMyListener);
Filter := TJIntentFilter.JavaClass.init;
Filter.addAction(StringToJString('scan.rcv.message'));
TAndroidHelper.context.getApplicationContext.registerReceiver(FBroadcastReceiver, Filter);
ScanDevice := TJScanDevice.Create; {creating scanner interface}
ScanDevice.setScanCodeEnterKey;
ScanDevice.setOutScanMode(0); {setting scanner to broadcast mode }
ScanDevice.openScan;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
TAndroidHelper.context.getApplicationContext.unregisterReceiver(FBroadcastReceiver);
ScanDevice.stopScan;
ScanDevice._Release;
end;
procedure TForm1.managebarcodescan(barcode: string);
begin
Edit1.Text := barcode;
end;
end.
Upvotes: 0
Views: 3558
Reputation: 1218
Here I posted a class to receive a simple broadcast from android send SMS func.
If you need that another intent starts your intent -
you need to attach a special JAR file to your project.
Here is the manual how to do it (use google translate)
Also check this(Launching activities and handling results in Delphi Android apps)
Upvotes: 1