Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
296 views
in Technique[技术] by (71.8m points)

delphi - How to pass boolean (or integer) to intent and read it (to detect that my activity was started from Android AlarmManager)?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...