In my app, developed with XE7 for Android/iOS, I have a form for scanning barcodes. Upon a found barcode, my app validates whether it is an acceptable barcode or not. Following tutorials here: http://www.fmxexpress.com/qr-code-scanner-source-code-for-delphi-xe5-firemonkey-on-android-and-ios/
Currently I am testing on Android and I am able to integrate scanning and reading of barcodes, but the 'onBarCode' event does not fire when returned from the shared Activity of finding the barcode. Same code worked well with previous versions of Rad Studio ( XE4, XE5, XE6) but now in XE7 it does not.
Here are some snippets of code:
...
begin
Scanner := TAndroidBarcodeScanner.Create(true);
Scanner.OnBarCode := BarcodeHandler;
Scanner.Scan;
end;
procedure TmScannerForm.BarcodeHandler(Sender: TAndroidBarcodeScanner;
BarCode: String);
begin
text1.Text := Barcode;
memo1.PasteFromClipboard;
AddBarcode(BarCode, true);
end;
AddBarCode is the even I used to validate and add barcode to a list, but I didnt include it, because that code isn't the problem - it's not even triggering. The Text1.text:=Barcode and memo1.paseFromClipboard were in their for validating the even wasn't firing too. I can confirm the barcodes are being read because if I tap and manually paste, the barcode shows.
Why is this not working on XE7 as it did in previous versions of Rad Studio?
Andrea Magni has a more elegant solution than the timer on his blog based on event handling.
I would comment to send the link but I don't have enough reputation.
The link to his blog is :
http://blog.delphiedintorni.it/2014/10/leggere-e-produrre-barcode-con-delphi.html
Maybe this can help you. The blog is in Italian though but the sources are provided and are explaining by themselves.
There is a source code fragment on http://john.whitham.me.uk/xe5/ which looks useable (based on Zxing):
intent := tjintent.Create;
intent.setAction(stringtojstring('com.google.zxing.client.android.SCAN'));
sharedactivity.startActivityForResult(intent,0);
The code in the linked article also shows how to receive the Intent result. (I don't work with Delphi on Android so I am not sure if that part uses a best practice - TTKRBarCodeScanner uses a workaround with a Timer and the Clipboard).
I would try this as an alternative to see if works.
This code works to me!
Set timer enabled to true when you run your scan code
procedure Tform.Timer1Timer(Sender: TObject);
begin
if (ClipService.GetClipboard.ToString <> '') then
begin
timer1.Enabled:=false;
zSearch.Text := ClipService.GetClipboard.ToString;
//Do what you need
end;
end;
This code to me works fine!
in andorid.BarcodeScanner
function TAndroidBarcodeScanner.HandleAppEvent(AAppEvent: TApplicationEvent;
AContext: TObject): Boolean;
var
aeBecameActive : TApplicationEvent;
begin
aeBecameActive := TApplicationEvent.BecameActive;
if FMonitorClipboard and (AAppEvent = aeBecameActive) then
begin
GetBarcodeValue;
end;
end;
Related
I am using Delphi Enterprise version 10.2.3 with Android SDK ver 24.3.3 32bit. I tried a very simple program with only one button. The Onclick is simply the following:
ShowMessage('1');
ShowMessage('2');
ShowMessage('3');
ShowMessage('4');
The result I got on my Samsung phone when clicking on the button is:
4
3
2
1
Of course I am expecting to get
1
2
3
4
This is not my first Android Program. The previous ones runs smoothly. But when I got strange errors on my latest program, I found that programming steps are carried out in reverse. I am also scared now to recompile the previous apps, just in case I am getting this strange behavior. So I just make a new program (above) to test, but got the same results. I also disabled the Antivirus Avast program, and even try it on another Samsung device.
Help will be very much appreciated. At this moment I am really confused and not sure what next steps to take to solve the problem. Please help me!
On mobile platforms, ShowMessage behaves asynchronously. The call finishes instantaneously, it does not wait for the user to close the dialog box.
Try this code:
function TForm1.MyShowMessage(const Msg: String): TModalResult;
var
MR: TModalResult;
begin
MR := mrNone;
TDialogService.MessageDialog(Msg, TMsgDlgType.mtConfirmation,const [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbYes, 0,
procedure(const AResult: TModalResult)
begin
MR := AResult;
end);
while MR = mrNone do begin
Application.ProcessMessages;
CheckSynchronize;
end;
Result := MR;
end;
I'm using Delphi 10.3 Community Edition and want to use the WRITE_SETTINGS in my application to set the brightness.
I could get it managed to implement this procedure to call the settings dialog:
procedure RequestWriteSettings;
var
Intent: JIntent;
begin
Intent := TJIntent.JavaClass.init(TJSettings.JavaClass.ACTION_MANAGE_WRITE_SETTINGS);
TAndroidHelper.Activity.startActivity(Intent);
end;
I can call this procedure in my application, the dialog appears and I can set the necessary permissions.
But I don't want to call this procedure permanently, because that's not user friendly.
I need to check if the WRITE_SETTINGS permission is already set, but I don't know how to implement this in Delphi/Firemonkey.
What I could find is that one has to call the "Settings.System.canWrite(context)" function, but I only can find samples for java.
Calling these kind of java routines in Delphi isn't that easy. I'm searching around already for some weeks and tried "things on my own", but still without success.
Can someone provide the code line how this routine has to be called in Delphi?
Thanks so much in advance!
MPage
Example code for checking WRITE_SETTINGS:
uses
Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Provider, Androidapi.JNI.Net, Androidapi.Helpers;
procedure TForm1.RequestWriteSettingsButtonClick(Sender: TObject);
begin
if not TJSettings_System.JavaClass.canWrite(TAndroidHelper.Context) then
StartWritePermissionsActivity
else
ShowMessage('System says app can write settings');
end;
procedure TForm1.StartWritePermissionsActivity;
var
LIntent: JIntent;
begin
LIntent := TJIntent.JavaClass.init(TJSettings.JavaClass.ACTION_MANAGE_WRITE_SETTINGS);
LIntent.setData(TJnet_Uri.JavaClass.parse(StringToJString('package:').concat(TAndroidHelper.Context.getPackageName)));
TAndroidHelper.Context.startActivity(LIntent);
end;
In the meanwhile I found a solution for myself, but I think Dave's is better. ;-)
That's what I found with the "trial and error" method:
function HasWriteSettings: Boolean;
begin
// Call canWrite to check for permission WRITE_SETTINGS
Result := TJSettings_System.JavaClass.canWrite(TAndroidHelper.Context.getApplicationContext);
end;
I'm using Delphi 10 Seattle trail version for developing mobile application. And I tried to create new android mobile application which contains only TEditBox. And then compiled by setting the option as "Release". Then, generated the .apk file and then provided the file to the user. And when the user tried to click the edit box, the application raises the error message that "The Appname is not responding".
The user is using the Lennova A5000 and the Os is Android 5.0.2.
And the same application is running in my Moto g2 (5.0.2) and Micromax Yureka.
Please provide me is there any solution.
Also, I have updated the app in google app store. Then, it is showing as incompatible application for this device (Lennova A5000).
And also I have updated all the android SDK packages. After that also, it is raising the same issue.
I think this may be problem to Embarcadreo Delphi or any missing packages? Dont know what to do.
Thanks in advance.
Atlast I got the solution from Embarcadreo website. Please follow the mentioned steps.
1.Copy FMX.Platform.Android.pas to the project folder from source/fmx folder
and add the copied files to the project.
Then, do the changes in the following procedures.
procedure TPlatformAndroid.RunOnUIThread(Proc: TThreadProcedure);
procedure TPlatformAndroid.RunOnUIThread(Proc: TThreadProcedure);
begin
//MainActivity.runOnUiThread(TSimpleProcedureRunner.Create(Proc));
CallInUIThread(
procedure()
begin
Proc;
end);
end;
procedure TPlatformAndroid.SynchronizeOnUIThread(Proc: TThreadProcedure);
procedure TPlatformAndroid.SynchronizeOnUIThread(Proc: TThreadProcedure);
var
Runner: TSimpleProcedureRunner;
begin
// CallInUIThread(
// procedure()
// begin
// Runner := TSimpleProcedureRunner.Create(Proc);
// MainActivity.runOnUiThread(Runner);
// Runner.Event.WaitFor;
// end);
CallInUIThreadAndWaitFinishing(
procedure()
begin
Proc;
end);
end;
procedure TPlatformAndroid.SetClipboard(Value: TValue);
procedure TPlatformAndroid.SetClipboard(Value: TValue);
var
Setter: TClipboardSetter;
begin
Setter := TClipboardSetter.Create(Value.ToString);
CallInUIThread(
procedure()
begin
SharedActivity.runOnUiThread(Setter);
end);
Setter.Done.WaitFor(INFINITE);
end;
function TPlatformAndroid.GetClipboard: TValue;
function TPlatformAndroid.GetClipboard: TValue;
var
Getter: TClipboardGetter;
begin
Getter := TClipboardGetter.Create;
CallInUIThread(
procedure()
begin
SharedActivity.runOnUiThread(Getter);
end);
Getter.Done.WaitFor(INFINITE);
Result := Getter.Value;
end;
Then, Rebuild the project. After doing this every thing is working fine.
I am a newbie to Delphi XE5 and currently developing Android platform applications on my Windows desktop using Delphi XE5.
I have two forms(Form1 and Form2) and tried to show Form2 in modal way on Form1 according to the way showed in Marco's RAD Blog(http://blog.marcocantu.com/blog/xe5_anonymous_showmodal_android.html).
But result was not as expected.
procedure TForm1.Button1Click(Sender: TObject);
var
frm2: TForm2;
begin
frm2 := TForm2.Create(nil);
ShowMessage('before frm2.ShowModal...');
frm2.ShowModal (
procedure(ModalResult: TModalResult)
begin
if ModalResult = mrOK then
if frm2.ListBox1.ItemIndex >= 0 then
edit1.Text := frm2.ListBox1.Items [frm2.ListBox1.ItemIndex];
frm2.DisposeOf;
end
);
ShowMessage('after frm2.ShowModal...');
end;
I wrote above code and run the application on an Android device.
I clicked the Button1, then I got the messagebox "before frm2.ShowModal... ", next "after frm2.ShowModal...", and then Form2 was showed.
I expect that the order should be 1)"before frm2.ShowModal... " message, 2) Form2 being showed, and 3) "after frm2.ShowModal..." message.
What's wrong with me?
The call to the anonymous ShowModal is not blocking, which means that any code after the ShowModal will be executed first.
One note here. Calling frm2.DisposeOf is wrong.
You must use this pattern:
declare
procedure TFrm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
See http://www.malcolmgroves.com/blog/?p=1585.
The documentation has been corrected in XE7, Using FireMonkey Modal Dialog Boxes, but this pattern can be used in all Delphi versions.
Conclusion: if you want to execute code after the modal dialog is closed, put that code inside the anonymous method.
I am developing inapp-Purchase in Delphi XE6.
Based on embarcadero documentation I create an InAppPurchase component as below:
FInAppPurchase := TInAppPurchase.Create(self);
{$IFDEF Android}
FInAppPurchase.ProductIDs.Add(License5And);
FInAppPurchase.ProductIDs.Add(License10And);
FInAppPurchase.ProductIDs.Add(License20And);
FInAppPurchase.ProductIDs.Add(License50And);
{$ENDIF}
{$IFDEF IOS}
FInAppPurchase.ProductIDs.Add(License5);
FInAppPurchase.ProductIDs.Add(License10);
FInAppPurchase.ProductIDs.Add(License20);
FInAppPurchase.ProductIDs.Add(License50);
{$ENDIF}
FInAppPurchase.OnSetupComplete := InAppPurchase1OnSetupComplete;
FInAppPurchase.OnConsumeCompleted := InAppPurchase1ConsumeCompleted;
FInAppPurchase.OnError := InAppPurchase1Error;
FInAppPurchase.OnProductsRequestResponse := InAppPurchase1ProductsRequestResponse;
FInAppPurchase.OnPurchaseCompleted := InAppPurchase1PurchaseCompleted;
FInAppPurchase.OnRecordTransaction := InAppPurchase1RecordTransaction;
FInAppPurchase.OnVerifyPayload := InAppPurchase1VerifyPayload;
{$IFDEF Android}
FInAppPurchase.ApplicationLicenseKey := myLicenseKeyFromGoogleDeveloperConsole;
{$ENDIF}
Then in InAppPurchase1OnSetupComplete I Called the FInAppPurchase.QueryProducts then it goes into InAppPurchase1ProductsRequestResponse and products and InavlidProductIDs both are empty. I don't know what I missed. Any help will be appreciated.
I check my products in google developer console all of them are 'Active' and as Type of 'Managed'.
p.s. Code is working perfect on ios Device.
I lost a lot of time to understand the problem.
After I studied the source code I have understand that in Android the Events are asynchronous, you must wait the "QueryProducts" result.
In order to fix this problem I created a TTimer that wait 5 second before it read "InAppPurchase.IsProductPurchased"
(I'm sorry for bad English)
It seems the app should be published for alpha or beta testing.
Instead of uploading for production I need to upload it for alpha first then publish it. after that the products are shown.
I developed the interface with the market starting from the example CapitalITrivia in Enbarcadero. I had the same problem and I read the answer that was given here.
I tried it and actually works. But this solution did not satisfy me because it depends on a delay not justified.
I realized that in InAppPurchaseSetupComplete was called the QueryProducts function and then I performed IsProductPurchased.
If I move the IsProductPurchased test in InAppPurchaseProductsRequestResponse function I get the expected result without introducing the delay.