did someone already find the correct way to program an alarm clock using DEPHI XE 5 and Android OS?
I found this code , but it does not work/compile at all:
procedure TNotificationsForm.btnSendScheduledNotificationClick(Sender: TObject);
var
Notification: TNotification;
begin
{ verify if the service is actually supported }
if NotificationC.Supported then // compile error here
begin.Supported
Notification := NotificationC.CreateNotification; // compile error here
try
Notification.Name := 'MyNotification';
Notification.AlertBody := 'Delphi for Mobile is here!';
{ Fired in 10 second }
Notification.FireDate := Now + EncodeTime(0,0,10,0);
{ Send notification in Notification Center }
NotificationC.ScheduleNotification(Notification);
finally
Notification.DisposeOf;
end;
end
end;
The first error is that NotificationC.Supported this property does not exist
You should mention that the code is based on one of the sample applications distributed with XE5. They can be found in the Start Menu entry for XE5 under Samples, or in the default C:\Users\Public\Documents\RAD Studio\12.0\Samples\MobileCodeSnippets\Notifications folder (Windows 7).
It appears you've forgotten to drop the TNotificationCenter component (available on the Component Palette's Services page) on the form and name it NotificationC as the demos do. Once you've done that, your code compiles just fine.
When you mention that you get a "compile error" in a question here, it's important to include the error message. We can't see your screen from where we are. :-) You have that exact information right in front of you, so there's no excuse for not including it. The Messages window will even copy the exact message to the clipboard for you to paste here, if you right-click the error line.
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've created simple Android Service on 10.2.3 and pinned it to my Android App same as it stands in docs. However, there where no libProxyAndroidService.so in {$BDS}/lib/android/release, I've copied it from debug dir. Next thorn made by Embarcadero to me was hanging of whole application while calling
TLocalServiceConnection.StartService('somename');
I have installed 10.3.1 with hope that this bug is eliminated in this release, but it did the same.
Running app in debug mode, I have putted some breakpoints in System.Android.ServiceApplication, when steping over and over by code, it crashed in System.InitUnits, line 23357:
try
while I < Count do
begin
P := Table^[I].Init;
Inc(I);
InitContext.InitCount := I;
if Assigned(P) and Assigned(Pointer(P^)) then
begin
{$IF defined(MSWINDOWS)}
TProc(P)();
{$ELSEIF (defined(POSIX) and defined(CPUX86)) and defined(ASSEMBLER)}
CallProc(P, InitContext.Module^.GOT);
{$ELSE}
TProc(P)(); << 23357 crashing
{$ENDIF}
end;
After execution of malfunctional P, UI thread hangs out, Service is never executed, but in background Android App is still executing code (new threads in message log)
Edit:
I've checked what is under P^
This is initalization part of unit FMX.Platform
https://quality.embarcadero.com/browse/RSP-17857
It's old bug, never fixed by Embarcadero
Just remove all things which use FMX.Types unit, remove this unit from evey uses.
Then set ClassGroup to TPersistent
Wasted hours :|
procedure TPlatformAndroid.BindAppGlueEvents;
var
AndroidAppGlue: TAndroidApplicationGlue;
begin
AndroidAppGlue := PANativeActivity(System.DelphiActivity)^.instance; // <------- Error occurs here
AndroidAppGlue.OnApplicationCommandEvent := HandleApplicationCommandEvent;
AndroidAppGlue.OnContentRectEvent := HandleContentRectChanged;
AndroidAppGlue.OnInputEvent := HandleAndroidInputEvent;
end;
Related issues: RSP-12199 and RSP-13381. FMX seems to have a lot of problems related to use of System.DelphiActivity in a service. And for good reason. DelphiActivity probably shouldn't exist in the first place! You are not supposed to hold on to references to the Activity object in the first place. And a Service doesn't even require an Activity to run! Apps and Services alike run as Contexts instead (the Activity and Service classes both derive from the Context class), so if you need to hold a reference to something, hold one to the Context that the code is running in (which FMX also does). What is FMX doing with DelphiActivity that is so important that it can't be done in other (safer) ways?
Conclusion: There is nil in System.DelphiActivity in Services so loading FMX units will create a crash in initUnits.
PDFed link with bug explanation: https://www.docdroid.net/TfUjBwg/bug.pdf
I can setup my android app to start at specified time with Android AlarmManager. It works nice, I used this manual and this forum for details (use google translator).
So I'm creating DEX file from Java code (from XE7 you can simply attach JAR without creating dex(!)). To detect if My app was started from AlarmManager I decided to put boolean var to intent, using this java manual from stackoverflow, so I added to java code this line:
TestLauncher.putExtra("StartedFromAM", true);
Full Java code, that will be compiled to jar (or dex):
package com.TestReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent TestLauncher = new Intent();
TestLauncher.setClassName(context, "com.embarcadero.firemonkey.FMXNativeActivity");
TestLauncher.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TestLauncher.putExtra("StartedFromAM", true);
context.startActivity(TestLauncher);
}
}
So now in theory my Intent has StartedFromAM argument.
It compiles to dex file ok, the problem is I can't read this boolean from Delphi code - it is always = 0 (false).
I tried this:
ShowMessage(SharedActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage(MainActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
Update 1
Thanks to Mr. Blong I already got right solution on how to detect that my activity was started from Android AlarmManager, this update is just about PutExtra in Java Code and reading extra value from intent from Delphi. You can skip it if you want.
Now I know that I can connect JAR files (I have Berlin upd 2), without creating dex.
So I created new jar file - which full java code I showed above.
Then I created new project, and setup alarm with this code
procedure SetAlarmWakeUpAdnroid(aSeconds: integer);
function getTimeAfterInSecs(Seconds: Integer): Int64;
var
Calendar: JCalendar;
begin
Calendar := TJCalendar.JavaClass.getInstance;
Calendar.add(TJCalendar.JavaClass.SECOND, Seconds);
Result := Calendar.getTimeInMillis;
end;
var
Intent: JIntent;
PendingIntent: JPendingIntent;
vRes: boolean;
begin
Intent := TJIntent.Create;
Intent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity'));
PendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 1, Intent, 0);
TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30),
PendingIntent);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetAlarmWakeUpAdnroid(30);
end;
Then I added OnFormCreate event
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage('StartedFromAM =' + TAndroidHelper.Activity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage('EXTRA_ALARM_COUNT = ' + TAndroidHelper.Activity.getIntent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0).ToString);
end;
When Alarm manager started my app, I got EXTRA_ALARM_COUNT = 1 and StartedFromAM = 0.
There are a few things to say in reply to this question:
1) The principle works fine. If the Java code has been correctly compiled and correctly linked in, then when your activity is invoked by the AlarmManager via your BroadcastReceiver, code like this will operate as you expect:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getBooleanExtra(StringToJString('StartedFromAM'), False) then
lblInfo.Text := 'Started by Alarm Manager through Broadcast Receiver';
2) There is a potential gotcha with Delphi's inclusion of Java .jar files. In the absence of any additional evidence I will assume you have hit this in your situation where your code looks viable but appears to not be functioning.
When working with a .jar file that is included into your Delphi Android project, if you change or rebuild the .jar file, Delphi has an irksome tendency to not notice it has been updated, and so still links in your originally added version of the .jar.
To overcome this you can clean the project (right click on the project name in the Project manager tree control and choose Clean). If you want to be absolutely definitely sure that you have addressed the issue you should:
clean the project (ensuring the project's Android output directory gets removed)
remove the .jar file from the project's Android, Libraries list
close the project in Delphi
rebuild your .jar file
reopen the project in Delphi
re-add the .jar file to the project's Android, Libraries list
I hit this problem myself while looking at this alarm manager scenario.
Note I refer to a .jar file. That is what you add to your project from Delphi XE7 onwards. In XE6 you must create a merged classes.dex file from Delphi's classes.dex and your .jar file and work with that, and since the question refers to creating a DEX file, maybe the issue comes in following the prescribed steps? This is a much more cumbersome exercise than adding a .jar to the project.
3) The linked source article covers 2 options for invoking your application from the AlarmManager. You've looked at the approach that goes via a broadcast receiver, which you have implemented in Java - that added complications for you to build that up.
The other approach cited in that article has the AlarmManager directly trigger your activity. Now you may say "Well how do I know if the activity was triggered through an alarm, when my broadcast receiver is out of the picture?" and the answer would be that the activity intent will automatically contain an integer extra called EXTRA_ALARM_COUNT.
This means you can write some code like this, say in your OnCreate event handler, and entirely avoid custom Java code:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0) > 0 then
lblInfo.Text := 'Started by Alarm Manager through FMX Activity';
4) You'll note that I am using TAndroidHelper.Activity instead of SharedActivity. The latter changed over to the former in Delphi 10 Seattle.
Good Morning,I have a confused problem.I'm writing a multi-device application to get data from web server. I'm Using Rad Studio XE8.When the application running, it raise error like this
Debugger Exception Notification
Project SmartManager.apk raised exception class Segmentation fault (11).
1.I create a WSDL Importer,the WSDL file location is 'http://60.12.81.154/MobileQueryService/services/MobileQueryDaoImpl?wsdl'
2.Add a button and two edit component to the app .The button Onclick event is to finish user login,the code is:
**
procedure TFrmUserLogin.LoginByWebService;
var
ret: string;
JSONObject: TJSONObject;
begin
try
ret := GetMobileQueryDaoImplPortType.Sys_Return_UserInfo(eUserNo.Text, ePwd.Text);
if ret <> '' then
begin
JSONObject := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(ret), 0) as TJSONObject;
...
end;
except
showmessage('login failure!')
end;
end;
**
when the APP Run to 'ret := GetMobileQueryDaoImplPortType.Sys_Return_UserInfo(eUserNo.Text, ePwd.Text);',it raise error "class Segmentation fault (11)".
3.The webserver is writen by Java ,running on Tomcat7,when the app raise error,I find the server is running Normal.I print the result,it is right.
4.this app is running normal on win32 or win64 platform,but when i switch to android,the error is raised.
5.I have tested 2 mobile phone.One is HuaWei P6, the Android version 4.2.The Other is HuaWei P9, the Android version is 6.0. The App is working OK on P6,but raised error On P9.
6.Yesterday,I tried another way to get data from wbeserver By using httpclient,
the code like this:
**
procedure TFrmUserLogin.LoginByHttp;
var HttpClient:TIDHttp;
ParamList:TStringList;
url:String;
retResponse:TStringStream;
i: Integer;
rt,ret: string;
begin
try
HttpClient:=TIdHTTP.Create(Application.Owner);
retResponse:=TStringStream.Create;
url:='http://60.12.81.154/MobileQueryService/servlet/UserLoginAction' ;
ParamList:=TStringList.Create;
ParamList.Add('userno='+eUserNo.Text);
ParamList.Add('password='+ePwd.Text);
HttpClient.Post(url,ParamList,retResponse);
...
end;
**
The error is same!!!
Then I replace 'HttpClient.Post(url,ParamList,retResponse);'
with
'HttpClient.Get(url+'?userno='+eUserNo.Text+'&password='+ePwd.Text,retResponse);'
It is working as expected.
I do not know why,can anyone help me ?
I debugged the problem and it stops at the following line of code in "System.pas" file :
dlclose(handle);
I found when the handle is 0,the error raised.And I checked the file in XE10,all the code using dlclose will check that weather the handle is 0,like this :
if handle<>0 then dlclose(handle);
Could it be said that it is a bug of XE8?
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;