0

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.

Community
  • 1
  • 1
alitrun
  • 1,127
  • 8
  • 14

1 Answers1

1

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:

  1. clean the project (ensuring the project's Android output directory gets removed)
  2. remove the .jar file from the project's Android, Libraries list
  3. close the project in Delphi
  4. rebuild your .jar file
  5. reopen the project in Delphi
  6. 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.

blong
  • 2,145
  • 13
  • 23
  • Thank you Blong so much! EXTRA_ALARM_COUNT is working nice. I also tried to putExtra from Java Code again as boolean and integer, with another names. I have also deleted this dex file from Delphi Deployment > cleaned up project > deleted Debug folder > then created dex again > build and deploy project - and still could not get it from intent. Maybe it does not put extra fields or deletes this code. Btw I got my classes.dex (from debug classes.dex) with size 2.5 mb (Delphi Berlin update 2). Thank you again for informing about EXTRA_ALARM_COUNT! – alitrun Feb 22 '17 at 20:09
  • Ah yes, you;re creating a .dex file. This implies you are using XE6 or maybe even XE5, at a pinch. I added a note about this, but I reckon it's strong odds the issue arises there. I can say that I have your code working in Delphi 10.1 Berlin with the broadcast receiver in a standalone .jar file just fine - the values are put in the intent and passed through as expected. There must be an issue in how you are getting your code into the .dex or how the ,dex is being referenced by Delphi in your case. I don't have access to XE6 but I'm glad you have a means of progress now. – blong Feb 22 '17 at 20:23
  • I can connect jar instead of DEX? That's a new info for me:) I'm using Delphi Berlin upd 2. And thanx for Blong again, now I can simply connect jar! :) Btw I have updated the question - I can't read boolean from intent even with jar on new project with latest Delphi. But you can skip this question, I already got the answer - it is just an academic interest. – alitrun Feb 22 '17 at 22:28
  • Re your update, now you have switched to having the alarm manager trigger your activity directly, skipping the broadcast receiver (and so the broadcast receiver Java code and .jar are not required), it is unsurprising your custom extra is not present in the intent. The broadcast receiver is not involved and so has no opportunity to add that custom extra Boolean into the launching intent. – blong Feb 22 '17 at 23:34
  • However if you tweak the alarm set-up to again reference your broadcast receiver then you should find your custom extra available in the activity's intent, as the broadcast receiver takes charge of invoking your activity at the behest of the alarm manager, and so its actions will affect the activity's intent object. – blong Feb 22 '17 at 23:34
  • Oh, now I see the difference. I should add 'com.TestReceiver.AlarmReceiver' (this is BroadCastReceiver) as author specified in his manual in example #1. Today you clarify some of serious details for me and I think for Delphi community, especially for new mobile developers.. Thank you! – alitrun Feb 23 '17 at 01:00