[SOLVED] LAMW: how to declare receivers in Manifests
lazarus / 43-Android
----------------------------------------------------------------------
jluixjurado · 2022-09-21 13:17
Hi there!
I'm trying to declare an SMS receiver in my app androidmanifest.xml.
The reason for that is that if I use a jBroadcastReceiver it only
works when the app is running, but the app is not opened when a new
SMS is coming an the app is not working, as it seems to use the
context-register receivers approach
(https://developer.android.com/guide/components/broadcasts)
The problem is that: I add these lines to the androidmanifest.xml:
But, when an SMS comes, the following message appears in catlog and
the app crashes:
java.lang.RuntimeException: Unable to instantiate receiver
es.jluixjurado.alejandriasmsrecibidos.jBroadcastReceiver ...
jBroadcastReceiver has no zero argument constructor
I've tried to learn by the Demos, but the only one related I've found
is in AppSMSWidgetProviderDemo1. The problem is that, although when I
drop a jSMSWidgetProvider in my app it automagically adds these lines
to the manifest:
and the app doesn't crash anymore, The system doesn't open the app
when a sms arrives and the app is closed.
Any idea?
Thanks in advance.
----------------------------------------------------------------------
jluixjurado · 2022-09-21 14:53
Ok. I've advenced (a bit).
I've added the constructor
public jBroadcastReceiver() {}
to the file ..\lazandroidmodulewizard\android_wizard\smartdesigner\jav
a\jBroadcastReceiver.java and, now, when receiving the SMS the error
in logcat is:
java.lang.NullPointerException: Attempt to invoke virtual method
'void ...Controls.pOnBroadcastReceiver(long, android.content.Intent)'
on a null object reference
So, the missing part is that I need to instantiate the object!!! But,
how? I've already seen the file ..\lazandroidmodulewizard\android_wiz
ard\smartdesigner\java\jBroadcastReceiver.create, with the content
public java.lang.Object jBroadcastReceiver_jCreate(long _Self) {
return (java.lang.Object)(new jBroadcastReceiver(this,_Self));
}
but I'm not sure what I should do.
Any help would be greatly appreciated!
----------------------------------------------------------------------
jluixjurado · 2022-09-21 22:14
After many (many) attempts, this id how far I've reached:
Change the originalonReceive method in jBroadcastReceiver with this:
@Override
/*.*/public void onReceive(Context ctx, Intent intent) {
mResultCode = 0;
switch (this.getResultCode()) {
case Activity.RESULT_OK: mResultCode = -1; break;
case Activity.RESULT_CANCELED: mResultCode = 0; break;
}
mResultData = this.getResultData();
mResultExtras = this.getResultExtras(true);
//controls.pOnBroadcastReceiver(pascalObj, intent);
//jluixjurado
//--------------------------------------jluixjurado
if (controls != null) {
controls.pOnBroadcastReceiver(pascalObj, intent);
//normal behaviour
} else {
String packageName = ctx.getPackageName();
Intent appIntent = new Intent();
appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName cn = new ComponentName(packageName,
packageName+".App");
appIntent.setComponent(cn);
PendingIntent pendingIntent =
PendingIntent.getActivity(ctx, 0, appIntent,
PendingIntent.FLAG_UPDATE_CURRENT); //FLAG_CANCEL_CURRENT);
try {
// Perform the operation associated with our
pendingIntent
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
Log.d("BroadcastReceiver","Intent ->
"+packageName+".App");
}
//--------------------------------------jluixjurado
}
This way the app doesn't crash when not running and a SMS is received,
but it doesn't release the main activity (and I don't know why,
because the intend seems to be ok). I've tried a variant with the same
outcome:
@Override
/*.*/public void onReceive(Context ctx, Intent intent) {
mResultCode = 0;
switch (this.getResultCode()) {
case Activity.RESULT_OK: mResultCode = -1; break;
case Activity.RESULT_CANCELED: mResultCode = 0; break;
}
mResultData = this.getResultData();
mResultExtras = this.getResultExtras(true);
//controls.pOnBroadcastReceiver(pascalObj, intent);
//jluixjurado
//--------------------------------------jluixjurado
if (controls != null) {
controls.pOnBroadcastReceiver(pascalObj, intent);
//normal behaviour
} else {
String packageName = ctx.getPackageName();
Intent appIntent = new Intent(packageName+".App");
Intent appIntent = new Intent();
appIntent.setClassName(packageName,packageName+".App");
//if (priorIntent != null) appIntent.putExtras(intent);
appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(appIntent);
Log.d("BroadcastReceiver","Intent ->
"+packageName+".App");
}
//--------------------------------------jluixjurado
}
I'm a bit frustrated right now...
----------------------------------------------------------------------
jluixjurado · 2022-09-25 21:01
Hi there!
I've finally got it!
The main problem was that from Android 10 (API level 29), there is a
restriction for starting activities from the background
(https://developer.android.com/guide/components/activities/background-
starts). In that link you can read that, to overcome that restriction,
your application has to obtain the permission SYSTEM_ALERT_WINDOW
(@jmpessoa , Could it be possible to add that permission to the list
on Proyect -> Proyect properties -> [LAMW] Android Project Properties,
so we don't have to insert it manually in AndroidManifest.xml?)
So, let's add it to AndroidManifest.xml:
After that, we add our Manifest-declared receivers to the
AndroidManifest.xml file like, for instance, this one to be notified
when a SMS is received:
Then, we change the code of
../android_wizard/smartdesigner/java/jBroadcastReciever.java:
The line
controls.pOnBroadcastReceiver(pascalObj, intent);
turns into:
if (controls != null) {
controls.pOnBroadcastReceiver(pascalObj, intent);
//normal behaviour
} else {
Context appContext = ctx.getApplicationContext();
String packageName = appContext.getPackageName();
Intent appIntent = new Intent();
appIntent.setClassName(packageName,packageName+".App");
appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
appIntent.putExtras(intent);
appContext.startActivity(appIntent);
}
In essence, the new code does the same thing if the app which owns the
jBroadcastReceiver is up and running but, if it isn't, the main
activity of that App is started, and the bundle of the broadcast
intent is copied to the new intent in charge of starting the activity.
The App is started and the OnActivityCreate method of the main
activity is called, giving it the new intent. As that intent IS NOT a
broadcast one, we shouldn't called with it directly the
jBroadcastReceiver OnReceiver method. Instead, inside OnActivityCreate
we should do something like this:
procedure TMainModule.OnActivityCreate(Sender: TObject;
intentData: jObject);
var
bundle : jObject;
newIntent : jObject; //new SMS_RECEIVED [or any other
broadcast event you want to handle] intent
begin
bundle := IntentManager.GetExtraBundle(intentData);
IntentManager.NewIntent();
IntentManager.SetAction('android.provider.Telephony.SMS_RECEIVED');
IntentManager.PutExtraBundle(bundle); //put the intentData
extras bundle inside the newIntent
newIntent := IntentManager.GetIntent();
OnReceiver(self, newIntent); //now we can call the
jBroadcastReceiver OnReceiver method
end;
I hope it can be helpful to someone.
@jmpessoa: It would be great if you consider to change the
jBroadcastReceiver.java in Github, as it doesn't change the normal
behaviour of the component and gives it more functionality (and, of
course, that way it wouldn't erase my modifications in the next LAMW
update ). Thanks in advance.
----------------------------------------------------------------------
jmpessoa · 2022-09-25 23:08
QuoteIt would be great if you consider to change the
jBroadcastReceiver.java in Github...
I will do!
Thank you!