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:
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.